matth
matth

Reputation: 573

Interaction between c++11 std::thread and class friend function

I'm having trouble understanding a compiler error I'm getting trying to use a function declared as a friend to a class in a c++11 std::thread object. I've created a small example to show the issue I'm having. Basically, when the compiler has only seen the friend function prototype of aa, it throws an undefined symbol error when that function is passed into a thread object. I'm using g++ 4.9.2.

//test.cpp
#include <thread>

class A {
public:
  friend void aa(A &p);
  void av(void);
};

void A::av() {
  std::thread t1(aa,std::ref(*this));
}

void aa(A &p) {
  p;
}

int main() {
  A ai;
  ai.av();
  return 0;
}

Compiler command:

g++ -o test test.cpp -g -O0 -std=c++11 -lpthread

I get the compiler error:

test.cpp: In member function ‘void A::av()’:
test.cpp:12:18: error: ‘aa’ was not declared in this scope
   std::thread t1(aa,std::ref(*this));

In the above, if I replace the line

std::thread t1(aa,std::ref(*this));

with

aa(*this);

This compiles just fine. Alternatively, if I add another prototype declaration of the function above the definition of A::av, like:

void aa(A &p);

It compiles fine with the thread object declaration.

So why is the compiler objecting when I try to declare the thread object with only the friend prototype?

I realize in this trivial example I could move the declaration of aa above the definition of A::av, however in practice I would like do something more complex where I have a derived class B containing B::av, and the definition of aa is logically placed in the implementation file of A, while the definition of class A with the prototype of aa is located in a header file included in the definition of class B. So is this a compiler bug, or an issue with the way I've declared something?

Upvotes: 3

Views: 939

Answers (1)

Mike Seymour
Mike Seymour

Reputation: 254721

With only an in-class declaration, the friend function is only available via argument-dependent lookup. To specify it by name without calling it, as you do in the definition of av, you'll need to declare it in the global namespace beforehand, or move the definition to an earlier point.

Upvotes: 5

Related Questions