SFINAE 与继承

SFINAE and inheritance

我正在寻找以下问题的解决方案:

#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);
}

如果两个 foo 方法都在同一个 class 中,或者我从正确的 class 强制 fooA::foo for std::stringB::foo 用于 int),但是我需要不止一个 class,因为基础 class 必须是可扩展的。我不能使用简单的专业化,因为我需要更多 SFINAE 功能,例如检测 std::pairstd::tuple 等。我也不想将 foo 方法从 class 移动到名称空间.你有什么想法我该如何解决这个问题?

这里B::foo隐藏了A::foo,你需要一个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");
    }
};

但是

来自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类型不算,所以你必须在参数中使用std::enable_if

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

注意:

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

应该是

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