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

c++ template enable_if unable to match function definition to an existing declaration


I am trying to define a template member function for a template class outside of the class as well as leverage SFINAE to effectively partially overload the function. A minimal example of what I am trying is:

Test.h:

template<typename T, size_t D>
class Test
{
public:
    Test(){}
    ~Test(){}

    template<size_t W = D, typename = int*>
    void do_something(Test&);
private:
    T data[D];
};

#include <type_traits>

template<typename T, size_t D>
template<size_t W, typename std::enable_if<W == 2, int>::type* = 0>
inline void Test<T, D>::do_something(Test &)
{
    exit(2);
}

template<typename T, size_t D>
template<size_t W, typename std::enable_if<W == 3, int>::type* = 0>
inline void Test<T, D>::do_something(Test &)
{
    exit(3);
}

Main.cpp:

int main(int, char**) {
    Test<float, 2> t1;
    Test<float, 2> t2;
    t1.do_something(t2);
    return 0;
}

However this code sample produces the error: C2244 'Test::do_something': unable to match function definition to an existing declaration. If I change

template<size_t W, typename std::enable_if<W == 2, int>::type* = 0>

to

 template<size_t W, typename Type>

and remove the other definition of do_something then the code will compile with no problem so I know that enable_if is the problem. So the question is: How do I use enable_if to achieve a partial overload effect without defining the function inside the class?

Should add that I am compiling with MSVS 2015.


Solution

  • You have to use std::enable_if also in declaration:

    template<typename T, std::size_t D>
    class Test
    {
    public:
        template<std::size_t W, typename std::enable_if<W == 2>::type* = nullptr>
        void do_something(Test<T, W> &);
    
        template<std::size_t W, typename std::enable_if<W == 3>::type* = nullptr>
        void do_something(Test<T, W> &);
    };
    
    
    
    template<typename T, std::size_t D>
    template<std::size_t W, typename std::enable_if<W == 2>::type*>
    void Test<T, D>::do_something(Test<T, W> &)
    {
        std::cout << 1 << std::endl;
    }
    
    template<typename T, std::size_t D>
    template<std::size_t W, typename std::enable_if<W == 3>::type*>
    void Test<T, D>::do_something(Test<T, W> &)
    {
        std::cout << 2 << std::endl;
    }
    

    Demo