4

Obviously it is possible to pass an rvalue reference to std::thread constructor. My problem is with definition of this constructor in cppreference. It says that this constructor:

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

Creates new std::thread object and associates it with a thread of execution. First the constructor copies/moves all arguments (both the function object f and all args...) to thread-accessible storage as if by the function:

template <class T>
typename decay<T>::type decay_copy(T&& v) {
    return std::forward<T>(v);
}

As far as I can check:

std::is_same<int, std::decay<int&&>::type>::value

returns true. This means std::decay<T>::type will drop rvalue reference part of argument. Then how std::thread constructor knows that which argument is passed by lvalue or rvalue references? Because all T& and T&& will be converted to T by std::decay<T>::type

Majid Azimi
  • 5,575
  • 13
  • 64
  • 113
  • "Applies lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to the type T, removes cv-qualifiers, and defines the resulting type as the member typedef type" http://en.cppreference.com/w/cpp/types/decay - where do you see that it drops references? – xaxxon May 15 '16 at 19:15
  • @xaxxon you are missing `::type`. – T.C. May 15 '16 at 19:45
  • @T.C. removed -- but why are they the same? – xaxxon May 15 '16 at 19:56
  • @xaxxon That's the "lvalue-to-rvalue" part. – T.C. May 15 '16 at 19:59
  • I see. it's not the rvalue that's going to an lvalue, it's the int going to an int&& – xaxxon May 15 '16 at 19:59

3 Answers3

5

The std::thread constructor knows the value category of its arguments, because it knows what Function and Args... are, which it uses to perfectly forward the its parameters to decay_copy (or equivalent).

The actual thread function doesn't know the value category. It's always invoked as an rvalue, with all rvalue arguments - which makes sense: the copies of f and args... are local to the thread, and won't be used anywhere else.

T.C.
  • 133,968
  • 17
  • 288
  • 421
2
auto s = std::decay_copy(std::string("hello"));

Is equivalent to:

template<>
std::string std::decay_copy<std::string>(std::string&& src) {
    return std::string(std::move(src));
}

std::string s = decay_copy<std::string>(std::string("hello"));
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
1

It is common problem of the perfect forwarding. If you want to restore information about rvalue in the function, you have to use std::forward std::forward . If you are interested in the value type detection you may read this value_category . From the description you can find the information how the compiler recognizes rvalue, xvalue, lvalue, prvalue, gvalue on compile time.

arturx64
  • 943
  • 4
  • 12