Search code examples
c++c++11c++14sfinaeenable-if

Is template enable_if function implementation possible?


Using c++14, I have some function declarations that resemble the following.

template <class... Args>
struct potato {
template <class T, class = std::enable_if_t<!std::is_same<T, int>::value>>
const T& blee(size_t blou) const;

template <class T, class = std::enable_if_t<std::is_same<T, int>::value>>
const T& blee(size_t blou) const;
};

Is it possible to implement the functions separately? From what I can tell, there is no way the compiler can figure out what is implementing what. For example :

template <class... Args>
template <class T, class>
const T& potato<Args...>::blee(size_t blou) const {
    // do something
}

template <class... Args>    
template <class T, class>
const T& potato<Args...>::blee(size_t blou) const {
    // do something
}

The enable_if information is lost at that point. Am I missing a trick in my toolbag to make this work? Note that I'd rather not use return type enable_if or argument enable_if as they are ungodly.

edit : Updated to represent my use-case better.


Solution

  • You don't really need enable_if for that:

    template<class T>
    const T& blee(size_t blou) const {
        // do something
    }
    
    template<>
    const int& blee<int>(size_t blou) const {
        // do something
    }
    

    Edit: since your functions are inside a class template, you will have to use tag dispatching:

    template<class... Args>
    struct potato {
        template<class T>
        void blee() const;
    
    private:
        void realBlee(std::true_type) const;
        void realBlee(std::false_type) const;
    };
    
    template<class... Args>
    template<class T>
    void potato<Args...>::blee() const {
        realBlee(std::is_same<T, int>());
    }
    
    template<class... Args>
    void potato<Args...>::realBlee(std::true_type) const {
        std::cout << "int\n";
    }
    template<class... Args>
    void potato<Args...>::realBlee(std::false_type) const {
        std::cout << "generic\n";
    }
    

    Live on Coliru

    or something similar, like a constexpr if:

    template<class... Args>
    struct potato {
        template<class T>
        void blee() const;
    
    private:
        void intBlee() const;
    };
    
    template<class... Args>
    template<class T>
    void potato<Args...>::blee() const {
        if constexpr (std::is_same_v<T, int>) {
            intBlee();
        } else {
            std::cout << "generic\n";
        }
    }
    
    template<class... Args>
    void potato<Args...>::intBlee() const {
        std::cout << "int\n";
    }
    

    Live on Coliru