对模板类重载操作符的模糊调用

时间:2012-06-15 10:01:02

标签: c++ templates operator-overloading

我有一个用于卷对象的模板化类,其中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;

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

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

为什么电话不明确?

3 个答案:

答案 0 :(得分:4)

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

我假设volume具有用户定义的类型。如果它有一个内置类型,那么我不会认为调用是不明确的,因为仅为了运算符重载解析的目的,有“实际”函数double operator+(double, double);等,即使在考虑模板之前也会选择它。

答案 1 :(得分:2)

假设Volume是您班级的名称。

Volume volume;

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

  1. 模板 类操作符+(Class c,dataType常量)
  2. 模板 类操作符+(数据类型常量,类c)
  3. 为什么?

    这些定义中的文字“类”没有意义。即使您打算发生这种情况,它也与'Volume'类相关。

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

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

    2. 因此,这两个对于行

      的编译器同样足够好
      volume+1.3
      

      即:从(1):

      Volume operator+(Volume c, double constant)
      

      来自(2):

      Volume operator+(Volume constant, double c)
      

      现在,编译器的含糊不清。

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

答案 2 :(得分:0)

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

如果你有一个&#34;卷&#34;要使用operator +的类型,可以使它们继承一个公共基类,然后可以将其用作模板中的参数类型。

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> { ... };