СФИНАЕ и наследство - PullRequest
       5

СФИНАЕ и наследство

0 голосов
/ 06 марта 2020

Я ищу решение следующей проблемы:

#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 находятся в одном классе, или я заставляю foo из соответствующего класса (A::foo для std::string и B::foo для int), однако мне нужно более одного класса, потому что базовый класс должен быть расширяемым. Я не могу использовать простую специализацию, потому что мне нужно больше функций SFINAE, таких как обнаружение для std::pair, std::tuple et c. Я также не хочу перемещать методы foo из класса в пространство имен. У вас есть идея, как я могу решить эту проблему?

1 Ответ

1 голос
/ 06 марта 2020

Здесь 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 :

Когда декларатор использования переносит объявления из базового класса в производный класс, функции-члены и шаблоны функций-членов в производном классе переопределяют и / или скрывают функции-члены и шаблоны функций-членов с помощью то же имя, список типов параметров, cv-qualification и ref-qualifier (если есть) в базовом классе (а не конфликтующие)

Тип возвращаемого значения не учитывается, поэтому необходимо используйте 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");
    }
};

Демо

Примечание: у вас также есть опечатка для

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)
}
...