Оператор перегрузки шаблона в производном классе

Учитывая базовый класс и производный класс, которые оба предоставляют условно разрешенные операторы для определенных типов параметров с использованием SFINAE:

#include <type_traits>

class Base
{
public:
    template<class T, std::enable_if_t<std::is_scalar_v<T>>* = nullptr>
    void operator>>(T& value) {
    }
};

class Derived: public Base
{
public:
    using Base::operator>>;

    template<class T, std::enable_if_t<!std::is_scalar_v<T>>* = nullptr>
    void operator>>(T& value) {
    }
};


int main(int argc, char *argv[])
{
    int foo;

    Base base;
    base >> foo; // this works

    Derived derived;
    derived >> foo; // this doesn't work, the operator from the base class is not considered
}

тогда вызов оператора, определенного в базовом классе, для экземпляра производного класса не будет работать, даже если его нужно было сделать видимым с помощью соответствующего объявления using Base::operator>>;. Почему? Как можно сделать оператор из базового класса пригодным для использования без повторения объявления/определения?

Проблема не возникает, если рассматриваемый оператор не является шаблоном в базовом классе.

Изменить: протестировано с помощью msvc 15.9.7, а также clang.


person Cybran    schedule 29.03.2019    source источник
comment
Сделайте операторы свободными функциями. Вы пробовали это?   -  person Kuba hasn't forgotten Monica    schedule 29.03.2019
comment
Я воспроизвожу проблему с clang++, но не с g++. Добавлю еще вопрос: кто прав?   -  person max66    schedule 29.03.2019
comment
Та же проблема с простым шаблонным методом (не обязательно оператором); Я предполагаю, что это ошибка clang++ и msvc.   -  person max66    schedule 29.03.2019


Ответы (1)


Я думаю, что проблема здесь в том, что объявление using только переносит объявления функций и шаблонов функций в производный класс, которые имеют сигнатуры, которые не переопределяются членами производного класса [namespace.udecl]/15. Так что этот код действительно не должен компилироваться.

Используйте бесплатные функции вместо членов класса, чтобы решить проблему:

#include <type_traits>

class Base
{
public:
    template<class T, std::enable_if_t<std::is_scalar_v<T>>* = nullptr>
    friend void operator>>(Base&, T& value) {
    }
};

class Derived: public Base
{
public:
    template<class T, std::enable_if_t<!std::is_scalar_v<T>>* = nullptr>
    friend void operator>>(Derived&, T& value) {
    }
};

int main()
{
    int foo;

    Base base;
    base >> foo;

    Derived derived;
    derived >> foo;
}

живой пример здесь

person Michael Kenzel    schedule 29.03.2019