C++模板,模棱两可的重载

C++ template, ambiguous overload

本文关键字:重载 模棱两可 模板 C++      更新时间:2023-10-16

出于某种原因,我有两个类使用模板实现运算符"+",(我这样做是因为我希望这两个类的所有孩子都能使用它)。

我已经归结为一个非常简单的代码,实现我想使用的内容:

#include <type_traits>
class A{};
template<typename T>
A operator+(T& lhs,int rhs){
  static_assert(std::is_base_of<A, T>::value, "T must inherit from A");
  A to_return;
  return to_return;
}
class B{};
template<typename T>
B operator+(T& lhs,int rhs){
  static_assert(std::is_base_of<B, T>::value, "T must inherit from B");
  B to_return;
  return to_return;
}

int main()
{
  A u;
  A v = u+1;
}

编译时,编译器(g++ 或英特尔)返回以下错误:

  • G++:main.cpp:25:11:错误:"u + 1"中"运算符+"的不明确重载 主.cpp:25:11: 注意:候选人是: main.cpp:6:3: 注意:A 运算符+(T&, int) [T = A] main.cpp:15:3: 注意:B 运算符+(T&, int) [T = A]

  • ICPC : 主.cpp(25): 错误: 多个运算符 "+" 匹配以下操作数: 函数模板"运算符+(T &, int)" 函数模板"B 运算符+(T &, int)" 操作数类型为:A + 整数A v = u+1; ^

虽然它不是那么模棱两可,因为 v 应该是类型 A,所以只有第一个模板应该有效。

有什么想法可以解决这个问题,保留两个模板运算符吗?

或者另一个想法是让操作员为 A 和 B 的所有孩子工作?即对于A的所有C类孩子,我希望能够写 A w = u + 1; //where u is of type C.B也是如此。

谢谢

托尼

编辑:

按照Barry给出的答案,std::enable_if完成了这项工作。然而,事实证明,我所需要的是使用两个字体名,Barry提出的技术必须稍作修改以添加这种可能性:

#include <type_traits>
#include <iostream>
class A{};
template<typename T1,typename T2 = typename std::enable_if<std::is_base_of<A,T1>::value, A>::type>
A operator+(T1& lhs,T2& rhs){
  A to_return;
  return to_return;
}
class B{};
template<typename T1,typename T2 = typename std::enable_if<std::is_base_of<B,T1>::value, B>::type>
B operator+(T2& lhs,T2& rhs){
  B to_return;
  return to_return;
}

int main()
{
  A u;
  A w = u+u;
}

然后它工作正常,即使 T1 和 T2 是 A 的不同子级。

重载解析完全基于函数签名,即其名称、简历限定和参数类型。

对于您的第一个,即:

operator+(T& lhs, int rhs);

对于你的第二个,这也是:

operator+(T& lhs, int rhs);

由于它们是相同的,编译器无法区分两者 - 因此存在歧义。解决此问题的一种方法是将静态断言移动到返回类型并使用 SFINAE:

template<typename T>
typename std::enable_if<
    std::is_base_of<A, T>::value,
    A
>::type
operator+(T& lhs,int rhs){
    // stuff
}

您的其他运营商也是如此。这将起作用,直到您使用从两者派生的一些T尝试它,然后它将再次变得模棱两可。

或者,根据您实际使用lhs做什么,只需

A operator+(A& lhs, int rhs); // already accepts anything that derives from A