Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of std::thread constructor third template parameter?

This is how std::thread constructor declared (using Visual Studio 2015):

template<class _Fn,
class... _Args,
class = typename enable_if<
    !is_same<typename decay<_Fn>::type, thread>::value>::type>
explicit thread(_Fn&& _Fx, _Args&&... _Ax)

No questions regarding _Fn and _Args, however, that third class = ... confuses me totally. What does it do, how does it work and what is it for?

like image 774
Roman Avatar asked Oct 22 '17 14:10

Roman


2 Answers

That is an example of conditionally enabling the overload using SFINAE.

This overload shouldn't be considered for overload resolution if the first argument is of type std::thread.

Note that the raw source of C++ standard headers is not intended to be read. It is also not intended to be mimiced. C++ compiler implementors can do many things in their std header implementations that you cannot and should not do outside of those headers. The least of which is starting a variable with an _ followed by an upper case letter (which is banned in user code).

Examine the type of the default argument if _Fn is a std::thread, a reference to same, or reference to a cv modified same.

typename enable_if<
!is_same<typename decay<_Fn>::type, thread>::value>::type>

decay<_Fn>::type strips references and cv qualifications. It also converts references-to-functions to pointers-to-function and references-to-arrays to pointers-to-first-element, but that isn't important here.

Suppose _Fn was thread&. I will evalulate:

typename enable_if<
!is_same<typename decay<thread&>::type, thread>::value>::type>
typename enable_if<
!is_same<thread, thread>::value>::type>
typename enable_if<
!true>::type>
typename enable_if<
false>::type>
/* substitution failure occurs */>

enable_if<B>::type only exists if B is true; when _Fn is a thread, it is false, thus there is a substitution failure during overload resolution.

SFINAE means substitution failure is not an error, and instead of the compiler complaining, it simply removes this overload from consideration. And the thread(thread const&) (which I believe is =deleteed) constructor is found instead.

like image 99
Yakk - Adam Nevraumont Avatar answered Nov 09 '22 16:11

Yakk - Adam Nevraumont


The 3rd unnamed template parameter has a default value, which is used to satisfy the following requirement of the constructor of std::thread via SFINAE, to avoid the disturbance when the move constructor is intended to be invoked.

This constructor does not participate in overload resolution if std::decay_t<Function> is the same type as std::thread.

like image 39
songyuanyao Avatar answered Nov 09 '22 16:11

songyuanyao