Hacker News new | ask | show | jobs
by weerd 3431 days ago
Is this C++14? Can you please explain the "class = ..." template parameter?
2 comments

Yes, that's C++14.

First, "class = enable_if_t<!is_reference<T>::value>" is just "class Dummy = enable_if_t<!is_reference<T>::value>" that doesn't bother to name Dummy. It's providing a default template argument for a function template (this is a C++11 feature; in C++03, only class templates could have this).

Next, "enable_if_t<!is_reference<T>::value>" is a C++14 library feature (enable_if_t is an alias template; the Core Language gained alias templates in C++11, the library gained these in C++14). It is a synonym for "typename enable_if<!is_reference<T>::value>::type", which is more verbose (and what one had to type in C++11).

"is_reference<T>::value" is a C++11 type trait, that is true when T is X& or X&&, and false otherwise. (It's implemented with partial specializations, and a "static const bool value = true;" data member - actually constexpr these days, but no difference there. This is type traits 101.)

enable_if is a library helper for SFINAE. (Not necessarily C++11 Expression SFINAE; here, just C++03 classic SFINAE is being used.) Basically, enable_if<true>::type is void. enable_if<false>::type doesn't exist. This works with the Core Language's SFINAE rules to make function templates vanish from the overload set (if you don't know what SFINAE is, look it up; it's a little complicated, but it exists for good reasons, and it goes back to C++98).

So, this is how one writes a function template that vanishes under certain criteria. This is often desirable compared to doing different things for different types (that can often be done with "tag dispatch") or emitting compiler errors for certain types (that's a static_assert).

class = X is just an anonymous template type parameter with default value X, just like

    auto foo(int = 0);
declares a function with a int parameter with default value 0. In this case, it's just a conventional place to stick an expression in the declaration to trigger SFINAE. If you don't need SFINAE, you can also just place the condition in a static_assert in the definition

    template <class T>
    auto foo(T&&) {
        static_assert(!is_reference<T>::value, "call me with an r-value");
        ...
    }