为什么我的模板化函数不会将'int'提升为'T',其中'T'='double'?

时间:2015-10-05 08:52:42

标签: c++ templates c++11 c++14 type-promotion

我有一个用typename T模板化的类。它包含一个函数,

template <typename T, size_t a>
myClass<T,a> operator+(myClass<T,a> lhs, const T& rhs) {
    return lhs += rhs;
}

myClass<T,a> myClass<T,a>::operator+=(const T& rhs) {
    // Do addition, depends on 'a'.
    return *this;
}

当我打电话给你时,例如

myClass<double, 2> myObj_double_2(constructor args);
myObj_double_2 = myObj_double_2 + 5.2;

我没问题。

如果我打电话

myObj_double_2 = myObj_double_2 + 5;

然后编译器给我一条消息,如 - No match for 'operator+' (operand types are 'myClass<double, 2ul>' and 'int'). Candidates are ... note: deduced conflicting types for parameter 'const T' ('double' and 'int')

我能否以某种方式编写代码以允许传递转换为T的其他类型(例如,因为double(5)是有效的构造函数调用)?

3 个答案:

答案 0 :(得分:32)

当您使用模板参数推断时,一个模板参数的所有推论必须具有相同的结果。

在您的情况下,T的两个扣除产生doubleint,这两个扣除不相同,因此扣除失败。

你可以做的只是使用一个函数参数进行模板参数推导,并使另一个 undeduced

template <typename T, std::size_t A>
void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2);
//                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

请注意,std::common_type<T>::type基本上只是T,但因为arg2的类型现在是一个依赖类型(其名称显示在::的右侧),它没有推断出来。因此,只有第一个参数参与演绎并明确地生成T = double,然后第二个函数参数只有double类型,并且通常会进行转换。

根据经验,模板参数推导不会跨越::

答案 1 :(得分:17)

重载解析的编译器无法找到operator+的正确候选者,因为T已被扣除到double,文字5是整数。解决方案:

template <typename T1, typename T2, size_t a>
myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) {
    return lhs += T1(rhs);
}

答案 2 :(得分:8)

您遇到模板类型扣除问题。

这两个论点都给出了相同的立场&#34;在推断T的值时,在这种情况下,两个参数不一致 - 一个说T应该是int,另一个说T应该是double }。

解决此问题的正确方法是使用Koenig运营商。

制作+=+以及类的friend,并实施内联:

template<class T, size_t a>
class myClass {
  // etc
public:
  friend myClass operator+(myClass lhs, const T& rhs) {
    lhs += rhs;
    return std::move(lhs);
  }
  friend myClass& operator+=(myClass& lhs, const T& rhs) {
    // do addition, depends on `a`
    return *this;
  }
};

这种技术做得很奇怪。它根据类的模板类型创建非template运算符。当您调用++=时,可以通过ADL(Koenig查找)找到这些内容。

每个模板实例化都会获得其中一个运算符,但它们不是模板运算符,因此不会推导const T&,并且转换按预期进行。