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

C++ SFINAE enable_if_t in member function, how to disambiguate?


Suppose we have some SFINAE member function:

class foo{
    template <class S, class = std::enable_if_t<std::is_integral<S>::value, S>
    void bar(S&& s);
    template <class S, class = std::enable_if_t<!std::is_integral<S>::value, S>
    void bar(S&& s);
}

If we declared it as above, then how can we define them? Both of their function signatures would look like:

template <class S, class>
inline void foo::bar(S&& s){ ... do something ... }

I have seen examples where one returns an std::enable_if_t<...> like:

template <class S, class>
auto bar(S&& s) -> std::enable_if_t<!std::is_integral<S>::value, S>(...){
    ... do something ...
}

To disambiguate based off of the return type. But I don't want to return anything.


Solution

  • since default arguments are not part of a function signature, make them not default

    class foo{
        template <class S, typename std::enable_if<std::is_integral<S>::value, int>::type = 0>
        void bar(S&& s);
        template <class S, typename std::enable_if<!std::is_integral<S>::value, int>::type = 0>
        void bar(S&& s);
    };
    

    Live Demo


    EDIT: by popular demand, Here's the same code in C++17:

    class foo{
    public:
        template <class S>
        void bar(S&& s)
        {
            if constexpr(std::is_integral_v<S>)
                std::cout << "is integral\n";
            else
                std::cout << "NOT integral\n";
        }
    };
    

    constexpr if statements are special to the compiler because the branch is chosen at compile time, and the non-taken branch isn't even instantiated

    C++17 Demo