我正在尝试构建模板化的num类。此类需要具有类型为val
的公共属性T
,这是唯一的模板化参数。此外,如果提供一个值,则应使用该值初始化属性(val
)。为此,我编写了以下代码:
#include <iostream>
template<class T>
class Num {
public:
T val;
Num():val(0) { std::cout<<"default constr used"<<std::endl; }
Num(T value):val(value) {std::cout<<"constr (T value) used"<<std::endl; }
~Num() { std::cout<<"destructor used"<<std::endl; }
template<typename U>
Num operator+(const Num<U>& other) {
return val+other.value;
}
};
此外,我创建了main()
函数来测试程序,如下所示:
int main() {
std::cout << Num<int>(1) + Num<double>(2.0);
return 0;
}
但是程序的结果现在为3
。而我希望它是3.0
(类型为double
)。
答案 0 :(得分:10)
为此,您需要更改返回类型。
在您的代码中:
// vvv---- Means Num<T>
Num operator+(const Num<U>& other) {
return val + other.val;
}
实际上,您可以在类模板中键入不带模板参数的类的名称,这在某种程度上等同于编写Num<T>
。
您的函数总是返回第一个操作数的类型,而不管加法本身的类型如何。
您要从加法推断出这种类型:
auto operator+(const Num<U>& other) -> Num<decltype(val + other.val)> {
return val + other.val;
}
那样,根据C ++运算符规则,它始终是正确的返回类型。
答案 1 :(得分:9)
operator+
应该相对于其参数是对称的。最好将其实现为自由函数而不是成员函数,以使这种对称性更加明显。
例如(使用C ++ 14返回类型推导):
template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
using R = decltype(std::declval<T>() + std::declval<U>());
return Num<R>{x.val + y.val};
}
如果std::declval<T>()
和/或T
无法默认构造,则{p> U
就位于genericity。如果类型仅限于内置类型,例如int
和double
,则可以将其替换为T{}
或T()
:
using R = decltype(T{} + U{});
在C ++ 17中使用class template argument deduction可以进一步简化:
template<class T, class U>
auto operator+(const Num<T>& x, const Num<U>& y) {
return Num{x.val + y.val};
}