【问题标题】:C++ template, ambiguous overloadC++ 模板,模棱两可的重载
【发布时间】:2015-01-12 05:14:36
【问题描述】:

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

我已经得出了一个非常简单的代码来实现我想要使用的东西:

#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++ 或 intel)返回以下错误:

  • g++ : main.cpp:25:11: 错误: 'u + 1' 中'operator+' 的重载不明确 main.cpp:25:11: 注意:候选人是: main.cpp:6:3: 注意:A operator+(T&, int) [with T = A] main.cpp:15:3: 注意:B operator+(T&, int) [with T = A]

  • icpc : main.cpp(25): 错误:多个运算符“+”匹配这些操作数: 函数模板“A operator+(T &, int)” 函数模板“B 运算符+(T &, int)” 操作数类型为:A + int A v = u+1; ^

虽然它不像 v 应该是 A 类型那样模棱两可,但只有第一个模板应该工作。

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

或者让操作员为 A 和 B 的所有孩子工作的另一个想法? IE。对于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 的不同孩子。

【问题讨论】:

  • 只是不要构建模板操作员采取任何措施(我认为这是一个设计缺陷) - 更具体
  • *"虽然它不像 v 应该是 A 类型那样模棱两可,但只有第一个模板应该工作。" * 你是从哪里得到这个想法的?
  • T 可以是第一个(分别是第二个)A(分别是 B)的任何孩子。如果有任何方法可以告诉编译器,我对这个解决方案很好。
  • 您的 static_assert 不是可以从重载解决方案中排除重载的直接上下文,您是否尝试过SFINAE
  • 为什么不能模棱两可?解析中不考虑返回类型。

标签: c++ templates inheritance c++11 operator-overloading


【解决方案1】:

重载解析完全基于函数signature,它是它的名字、它的cv-qualifications和它的参数类型。

对于您的第一个,即:

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

【讨论】:

  • 这里是working sample,按照建议更改代码。
  • 谢谢,正是我想要的。事实上,“A operator+(A& lhs, int rhs);”做这份工作!
猜你喜欢
  • 1970-01-01
  • 2019-08-04
  • 2010-12-10
  • 2015-10-12
  • 2016-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
相关资源
最近更新 更多