SFINAE and inheritance

nadro :

I'm looking for a solution to a following problem:

#include <string>

class A
{
public:
    template <typename T>
    static typename std::enable_if<std::is_same<T, std::string>::value, void>::type foo(T val)
    {
        printf("std::string\n");
    }

    template<typename T, typename... Arg>
    static void multiple(Arg&&... arg)
    {
        T::foo(arg...);
    }
};

class B : public A
{
public:
    template <typename T>
    static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
    {
        printf("int\n");
    }
};

int main()
{
    std::string a;
    int b = 0;
    A::multiple<B>(a, b);
}

All works fine if both foo methods are in the same class or I force foo from proper class (A::foo for std::string and B::foo for int), however I need more than one class, because base class must be extendable. I can't use simple specialization, because I need more SFINAE features like detect for std::pair, std::tuple etc. I also don't want to move foo methods from a class to a namespace. Do you have any Idea how can I solve this issue?

Jarod42 :

Here B::foo hides A::foo, you need a using:

class B : public A
{
public:
    using A::foo;

    template <typename T>
    static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
    {
        printf("int\n");
    }
};

But

From namespace.udecl#15.sentence-1:

When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting)

Return type doesn't count, so you have to use std::enable_if in parameter:

class A
{
public:
    template <typename T>
    static void foo(T val, std::enable_if_t<std::is_same<T, std::string>::value, int> = 0)
    {
        printf("std::string\n");
    }

};

class B : public A
{
public:
    using A::foo;

    template <typename T>
    static void foo(T val, std::enable_if_t<std::is_same<T, int>::value, int> = 0)
    {
        printf("int\n");
    }
};

Demo

Note: you also have typo for

template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
    T::foo(arg...); // B::foo(string, int)
}

which should be

template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
    (T::foo(arg), ...); // B::foo(string), B::foo(int)
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=28307&siteId=1