为什么我的模板函数没有将 'int' 提升到 'T',其中 'T' = 'double'?

Why doesn't my templated function promote 'int' to 'T', where 'T' = 'double'?

我有一个 class 模板 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) 是一个有效的构造函数调用)?

关于重载决策的编译器无法为 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);
}

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

在你的例子中,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,通常的转换会发生。

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

您 运行 遇到模板类型推导问题。

在推导T的值时,两个参数都给出了"equal standing",在这种情况下,两个参数不一致——一个说T应该是int,另一个说 T 应该是 double.

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

制作 +=+ 等 class 的 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;
  }
};

这项技术做了一些奇怪的事情。它根据 class 的模板类型创建非 template 运算符。当您调用 ++=.

时,它们会通过 ADL(Koenig 查找)找到

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