Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does template<class = enable_if_t<...>> do?

I have been reading STL files to learn better ways to format my code, and to learn tricks to be more efficient. I have been reading the thread files and I can't figure out what some of the code does.

template<class _Fn,
    class... _Args,
    class = enable_if_t<!is_same<decay_t<_Fn>, thread>::value>>
    explicit thread(_Fn&& _Fx, _Args&&... _Ax)
    {   // construct with _Fx(_Ax...)
    ...
    }

std::enable_if_t is

template<bool _Test,
    class _Ty = void>
    using enable_if_t = typename enable_if<_Test, _Ty>::type;

template<class _Ty>
    struct enable_if<true, _Ty>
    {   // type is _Ty for _Test
    using type = _Ty;
    };

that code is all copyrighted in the thread and str1common STLs.

my only question is what does the class = enable_if_t<...> do?

like image 772
Cody W Avatar asked Apr 04 '18 20:04

Cody W


1 Answers

Look for S.F.I.N.A.E.: "Substitution Failure Is Not An Error".

See a possible implementation of std::enable_if (std::enable_if_t is only a helper using, C++14 introduced, to access the type in a simpler way)

template<bool B, class T = void>
struct enable_if {};

template<class T>
struct enable_if<true, T> { typedef T type; };

Is made so iff (if and only if) the template boolean value (the first template parameter) is true, std::enable_if<...>::type is defined (with the type in the second template parameter; void if unexpressed).

To make it simple, you have that, in your example

template<class _Fn,
    class... _Args,
    class = enable_if_t<!is_same<decay_t<_Fn>, thread>::value>>
    explicit thread(_Fn&& _Fx, _Args&&... _Ax)
    {   // construct with _Fx(_Ax...)
    ...
    }

enable_if_t (that is typename std::enable_if<...>::type) is available iff the first value (!std::is_same<typename std::decay<_Fn>::type, thread>::value) is true.

That is:

  • if !std::is_same<typename std::decay<_Fn>::type, thread>::value is true, the substitution class = enable_if_t<!is_same<decay_t<_Fn>, thread>::value>> is performed and the function is implemented

  • if !std::is_same<typename std::decay<_Fn>::type, thread>::value is false, the substitution class = enable_if_t<!is_same<decay_t<_Fn>, thread>::value>> fail, the function isn't implemented but this ins't an error (SFINAE).

Why the language permit this?

Because, by example, you can implement two version of the function

template<class _Fn,
    class... _Args, //  vvvv true case
    class = enable_if_t<true == is_same<decay_t<_Fn>, thread>::value>>
    explicit thread(_Fn&& _Fx, _Args&&... _Ax)
    { /* do something */ }

template<class _Fn,
    class... _Args, //  vvvvv false case
    class = enable_if_t<false == is_same<decay_t<_Fn>, thread>::value>>
    explicit thread(_Fn&& _Fx, _Args&&... _Ax)
    { /* do something else */ }

Suggestion: search for SFINAE and study it because is an important part of modern C++.

like image 134
max66 Avatar answered Oct 08 '22 00:10

max66