编辑:对之前的错误代码表示歉意。这是一个演示问题的可编译示例
我正在尝试实现一个简化为这种基本模式的访问者:
class Base {};
class BaseA : public Base {};
class BaseB : public Base {};
class DerivedA : public BaseA {
public:
int operator+(DerivedA const& a) const
{
return 10;
}
};
class DerivedB : public BaseB {
public:
int operator+(DerivedB const& b) const
{
return 10;
}
};
struct Adder
{
int operator()(BaseA const& a, BaseB const& b)
{
std::cout << "Addition is not supported for these types.";
return -1;
}
template <typename T, typename U>
int operator()(T const& a, U const& b)
{
return a + b;
}
};
int main()
{
DerivedA a;
DerivedB b;
Adder adder;
adder(a, a);
adder(b, b);
adder(a, b); // Compiler chooses templated function and fails if
// operator+ is not supported.
}
如果基本类型匹配(我已将其设置为不支持 operator+
的情况),我希望编译器选择非模板函数。然而,事实并非如此。
我相信我知道为什么(直接模板匹配比基类匹配好),以及Why is the compiler choosing this template function over an overloaded non-template function?的解决方案涉及替换失败不是错误 (SFINAE) 和 std::enable_if
似乎非常接近。
但是,该解决方案似乎只适用于返回 void
的函数。我如何调整 SFINAE 方法以允许我提供返回类型?
参见 http://ideone.com/uEbVmU对于编译错误:
Compilation error time: 0 memory: 3296 signal:0
prog.cpp: In instantiation of ‘int Adder::operator()(const T&, const U&) [with T = DerivedA; U = DerivedB]’:
prog.cpp:48:15: required from here
prog.cpp:37:22: error: no match for ‘operator+’ (operand types are ‘const DerivedA’ and ‘const DerivedB’)
return a + b;
^
prog.cpp:37:22: note: candidate is:
prog.cpp:12:13: note: int DerivedA::operator+(const DerivedA&) const
int operator+(DerivedA const& a) const
^
最佳答案
以下更改自:
template <typename T, typename U>
int operator()(T const& a, U const& b)
{
return a + b;
}
到:
template <typename T, typename U>
auto operator()(T const& a, U const& b) -> decltype(a+b)
{
return a + b;
}
允许您的代码编译。原因是在选择使用哪个重载时,实例化函数模板的签名导致编译错误(添加a+b
不匹配,因此decltype(a+b)
是一个错误)并且该函数从可能的重载集中删除。这使得非模板版本可用,并且每个人都赢了。
关于c++ - 我如何使用 SFINAE 确定非模板函数的优先级,同时还提供返回类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24185085/