派生类中的重载模板运算符

Overloading template operator in derived class

本文关键字:运算符 重载 派生      更新时间:2023-10-16

给定一个基类和一个派生类,它们都使用 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 进行测试。

我认为这里的问题是 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;
}

现场示例在这里