1

我有一个用于卷对象的模板类,它operator+=被实现为成员函数,并且operator+被实现为非成员函数:

template <typename Class>
Class operator+(Class c1, const Class& c2) {
   return c1 += c2;
}

// Add a constant to every element in the volume
template <typename Class, typename dataType>
Class operator+(Class c, dataType constant) {
   return c += constant;
}

template <typename Class, typename dataType>
Class operator+(dataType constant, Class c) {
   return c += constant;
}

然后我尝试编译以下内容:

volume + 1.3;

其中卷是从模板卷类派生的类型。这给了我以下错误:

error: ambiguous overload for ‘operator+’ in ‘volume + 1.3’

为什么通话模棱两可?

4

3 回答 3

4

您的第二个模板可以用Class = typeof(volume)and推断dataType = double,或者您的第三个模板可以用dataType = typeof(volume)and推断Class = double。编译器无法在它们之间进行选择,即使第三个模板很可能无法实例化。

我假设它volume有一个用户定义的类型。如果它具有内置类型,那么我认为该调用不会模棱两可,因为仅出于运算符重载决议的目的,double operator+(double, double);在考虑模板之前会选择“真实”函数等。

于 2012-06-15T10:06:53.010 回答
2

假设 Volume 是您的班级的名称。

Volume volume;

当需要解析volume + 1.3时,编译器会寻找合适的方法。它找到了其中两个。

  1. 模板类运算符+(类 c,数据类型常量)
  2. 模板类运算符+(数据类型常量,c类)

为什么?

这些定义中的字面“类”没有意义。即使您打算这样做,它也与“音量”类完全无关。

因此,编译器将其视为:1。

template <typename X, typename Y>
X operator+(X c, Y constant)
  1. 模板 Z 运算符+(Z 常数, X c)

因此,对于该行的编译器来说,这两者同样足够好

volume+1.3

即:来自(1):

Volume operator+(Volume c, double constant)

从(2):

Volume operator+(Volume constant, double c)

现在,它对于编译器来说是模棱两可的。

解决方案:我只能看到您必须为每种卷类型分别定义这些运算符的解决方案。

于 2012-06-15T10:40:37.827 回答
0

其他人解释了为什么您的代码不起作用。但总的来说,编写接受任何参数类型的函数模板是一个非常糟糕的主意。那只是要求模棱两可。

如果你有一个想要使用 operator+ 的“volume”类型列表,你可以让它们继承一个公共基类,然后你可以在模板中将其用作参数类型。

template<typename T>
struct VolumeBase { 
  T copy() const { return get(); }
  T const& get() const { return static_cast<T const&>(*this); }
};

template <typename Class, typename Class>
Class operator+(VolumeBase<Class> const& c, VolumeBase<Class> const& c1) {
   return c.copy() += c1.get();
}

template <typename Class, typename dataType>
Class operator+(VolumeBase<Class> const& c, dataType constant) {
   return c.copy() += constant;
}

template <typename Class, typename dataType>
Class operator+(dataType constant, VolumeBase<Class> const& c) {
   return c.copy() += constant;
}

不幸的是,您已经以这种方式将参数副本移动到模板的主体中,但如果它可以内联(对于这样一个简单的主体,我认为这没问题),这不会影响性能。所以每个卷类将被定义为

class MyVolumeClass : public VolumeBase<MyVolumeClass> { ... };
于 2012-06-15T15:05:14.200 回答