我有一个用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)是有效的构造函数调用)?
答案 0 :(得分:32)
当您使用模板参数推断时,一个模板参数的所有推论必须具有相同的结果。
在您的情况下,T
的两个扣除产生double
和int
,这两个扣除不相同,因此扣除失败。
你可以做的只是使用一个函数参数进行模板参数推导,并使另一个 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&
,并且转换按预期进行。