Search code examples
c++templatessfinaeenable-if

SFINAE and std::numeric_limits


I am trying to write a stream class that handles numerical and non-numerical data separately. Can someone explain to me why this code does not compile?

#include <iostream>
#include <cstdlib>

#include <type_traits>
#include <limits>

class Stream
{
public:
    Stream() {};

    template<typename T, typename std::enable_if_t<std::numeric_limits<T>::is_integer::value>>
    Stream& operator<<(const T& val)
    {
        std::cout << "I am an integer type" << std::endl;
        return *this;
    };

    template<typename T, typename std::enable_if_t<!std::numeric_limits<T>::is_integer::value>>
    Stream& operator<<(const T& val)
    {
        std::cout << "I am not an integer type" << std::endl;
        return *this;
    };
};

int main()
{
    Stream s;
    int x = 4;
    s << x;
}

Solution

  • Because you are doing SFINAE wrong, and you are also incorrectly using the trait (there is no ::value, is_integer is a boolean). The error with trait is trivial, the problem with SFINAE is that you gave a non-type template parameter to your operator<<, but you never provide an argument for it. You need to specify a default argument.

    Sample code:

    #include <cstdlib>
    #include <iostream>
    #include <type_traits>
    #include <limits>
    
    class Stream
    {
    public:
        Stream() {};
    
        template<typename T, std::enable_if_t<std::numeric_limits<T>::is_integer>* = nullptr>
        Stream& operator<<(const T& val)
        {
            std::cout << "I am an integer type" << std::endl;
            return *this;
        };
    
        template<typename T, std::enable_if_t<!std::numeric_limits<T>::is_integer>* = nullptr>
        Stream& operator<<(const T& val)
        {
            std::cout << "I am not an integer type" << std::endl;
            return *this;
        };
    };
    
    int main()
    {
        Stream s;
        int x = 4;
        s << x;
    }