为什么我的模板函数没有将 '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
的两次推导产生 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
,通常的转换会发生。
根据经验,模板参数推导不会跨越 ::
。
您 运行 遇到模板类型推导问题。
在推导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&
,并且会按预期进行转换。
我有一个 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
的两次推导产生 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
,通常的转换会发生。
根据经验,模板参数推导不会跨越 ::
。
您 运行 遇到模板类型推导问题。
在推导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
运算符。当您调用 +
或 +=
.
每个模板实例化都会获得这些运算符之一,但它们不是模板运算符,因此不会推导出 const T&
,并且会按预期进行转换。