My programs looks like below
#include <iostream>
#include <thread>
class A {
public:
void foo(int n ) { std::cout << n << std::endl; }
};
int main()
{
A a;
std::thread t1(&A::foo, std::ref(a), 100);
t1.join();
return 0;
}
When I compile it using the following command I get errors
g++ -o main main.cc -lpthread -std=c++11
Error:
In file included from /usr/local/include/c++/4.8.2/thread:39:0,
from check.cc:2:
/usr/local/include/c++/4.8.2/functional: In instantiation of ‘struct std::_Bind_simple<std::_Mem_fn<void (A::*)(int)>(std::reference_wrapper<A>, int)>’:
/usr/local/include/c++/4.8.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (A::*)(int); _Args = {std::reference_wrapper<A>, int}]’
check.cc:13:42: required from here
/usr/local/include/c++/4.8.2/functional:1697:61: error:no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (A::*)(int)>(std::reference_wrapper<A>, int)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/local/include/c++/4.8.2/functional:1727:9: error:no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (A::*)(int)>(std::reference_wrapper<A>, int)>’
_M_invoke(_Index_tuple<_Indices...>)
^
A member function is declared and defined in the class and called using the object of the class. A member function is declared in the class but defined outside the class and is called using the object of the class.
7. How to access members of the class inside a member function? Explanation: The members of a class can be used directly inside a member function. We can use this pointer when there is a conflict between data members of class and arguments/local function variable names.
This isn't the right place for a reference wrapper. A simple pointer suffices, though, and achieves the desired result:
std::thread t1(&A::foo, &a, 100);
EDIT: RETRACTION
Kerrek is correct here: I erroneously assumed that the std::thread constructor and std::bind were by design identical interfaces. However, the automatic conversion of arguments from reference_wrapper<A> to A& is specified for only std::bind in [func.bind.bind]/10:
The values of the bound arguments
v1, v2, ..., vNand their corresponding typesV1, V2, ..., VNdepend on the typesTiDderived from the call tobindand the cv-qualifiers cv of the call wrappergas follows:
- if
TiDisreference_wrapper<T>, the argument istid.get()and its typeViisT&;- ...
So this particular use of reference_wrapper<A> is not supported by std::thread, but is supported by std::bind. The fact that std::thread behaves identically to std::bind in this instance in other/older compilers is the bug, not the behavior of 4.8 line GCC releases.
I'll leave the incorrect answer here with this explanation in hopes that others won't make this same mistake in the future.
Short (but INCORRECT) answer
This is apparently a bug in the standard library included with GCC 4.8. The code is correctly compiled by:
Long (and also INCORRECT) answer:
The effects of the std::thread constructor
template <class F, class ...Args>
explicit thread(F&& f, Args&&... args);
are detailed in C++11 30.3.1.2 [thread.thread.constr]/4:
The new thread of execution executes
INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...)with the calls to
DECAY_COPYbeing evaluated in the constructing thread.
DECAY_COPY is described in 30.2.6 [thread.decaycopy]/1:
In several places in this Clause the operation
DECAY_COPY(x)is used. All such uses mean call the functiondecay_copy(x)and use the result, wheredecay_copyis defined as follows:template <class T> typename decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }
In the invocation in the OP std::thread t1(&A::foo, std::ref(a), 100); all three arguments are rvalues that DECAY_COPY will replicate into objects in the new thread's environment before the invocation, whose effect is described in 20.8.2 [func.require]/1:
Define
INVOKE(f, t1, t2, ..., tN)as follows:
(t1.*f)(t2, ..., tN)whenfis a pointer to a member function of a classTandt1is an object of typeTor a reference to an object of typeTor a reference to an object of a type derived fromT;((*t1).*f)(t2, ..., tN)whenfis a pointer to a member function of a classTandt1is not one of the types described in the previous item;- ...
For the code in the OP, f is a pointer to member function of class A with value &A::foo, t1 is an lvalue reference_wrapper<A> whose stored reference refers to a, and t2 is an int with value 100. The second bullet of 20.8.2/1 applies. Since t1 is a reference_wrapper, *t1 evaluates to the stored reference (per 20.8.3.3/1) and the invocation in the new thread is effectively
(a.*&A::foo)(100);
So yes, the standard describes the behavior of the OP exactly as expected.
EDIT: Oddly, GCC 4.8 correctly compiles the very similar example:
class A {
public:
void foo(int n) { std::cout << n << std::endl; }
};
int main()
{
A a;
auto foo = std::bind(&A::foo, std::ref(a), 100);
foo();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With