Search code examples
c++c++11enable-if

enable_if for functions with no return type pulled in it


I've recently encountered an interesting version of enable_if usage to conditionally enable a function with slightly better readability because the function's return type is not part of enable_if (see cleaner_usage):

#include <type_traits>

using maybe_integral = int /* = or float -- then won't compile */;
using return_type = int;

typename std::enable_if<std::is_integral<maybe_integral>::value, return_type>::type
traditional_usage()
{
    return 1;
}

template<typename std::enable_if<std::is_integral<maybe_integral>::value, int>::type = 0>
return_type cleaner_usage()
{
    return 2;
}

int main()
{
    return traditional_usage() + cleaner_usage();
}

For failure-case the mechanism is clear (no type member).

But how exactly does it work in other cases? Because it looks like int typedef field substituted into template type parameter with unexpected assignment.


Solution

  • In the success-case:

    template<typename std::enable_if<std::is_integral<float>::value, int>::type = 0>
    return_type cleaner_usage()
    {
        return 2;
    }
    

    would become equivalent to:

    template<int = 0>
    return_type cleaner_usage()
    {
        return 2;
    }
    

    Which is perfectly legal, given that some value types are allowed to appear in template parameter context. I believe these are formally called non-type template parameters, as described by §14.1/4:

    A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

    • integral or enumeration type,
    • pointer to object or pointer to function,
    • lvalue reference to object or lvalue reference to function,
    • pointer to member,
    • std::nullptr_t.