给出一个基类和一个派生类,它们都使用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进行了测试。
答案 0 :(得分:2)
我认为这里的问题是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;
}