Search code examples
c++c++11sfinaedecltype

Detect operator support with decltype/SFINAE


A (somewhat) outdated article explores ways to use decltype along with SFINAE to detect if a type supports certain operators, such as == or <.

Here's example code to detect if a class supports the < operator:

template <class T>
struct supports_less_than
{
    static auto less_than_test(const T* t) -> decltype(*t < *t, char(0))
    { }

    static std::array<char, 2> less_than_test(...) { }

    static const bool value = (sizeof(less_than_test((T*)0)) == 1);
};

int main()
{
    std::cout << std::boolalpha << supports_less_than<std::string>::value << endl;
}

This outputs true, since of course std::string supports the < operator. However, if I try to use it with a class that doesn't support the < operator, I get a compiler error:

error: no match for ‘operator<’ in ‘* t < * t’

So SFINAE is not working here. I tried this on GCC 4.4 and GCC 4.6, and both exhibited the same behavior. So, is it possible to use SFINAE in this manner to detect whether a type supports certain expressions?


Solution

  • You need to make your less_than_test function a template, since SFINAE stands for Substitution Failure Is Not An Error and there's no template function that can fail selection in your code.

    template <class T>
    struct supports_less_than
    {
        template <class U>
        static auto less_than_test(const U* u) -> decltype(*u < *u, char(0))
        { }
    
        static std::array<char, 2> less_than_test(...) { }
    
        static const bool value = (sizeof(less_than_test((T*)0)) == 1);
    };
    
    int main()
    {
        std::cout << std::boolalpha << supports_less_than<std::string>::value << endl;
    }