为什么模板类型参数不能隐式强制转换?
Why can't template type arguments be implicitly casted?
给定此代码:
template<typename T>
struct Type
{
T value;
};
template<typename T>
Type<T> operator+(const Type<T>& type, T val)
{
Type<T> type;
type.value += val;
return type;
}
int main()
{
Type<float> type;
type = type + 2;
}
我在 MSVC 中收到错误:
Error C2782 'Type<T> operator +(const Type<T> &,T)': template parameter 'T' is ambiguous
Error C2676 binary '+': 'Type<float>' does not define this operator or a conversion to a type acceptable to the predefined operator
Error no operator "+" matches these operands
我认为它只会将 int 提升为浮点数,但显然它不想这样做。有没有办法解决这个问题?
问题是编译器无法确定在Type<float> + int
中,你想调用operator+<float>
(强制从int
到float
的转换(而不是operator+<int>
(强制从Type<float>
到Type<int>
的转换(。当然,第二种解释会导致错误,但此时已经检测到并报告了歧义。
在这种特定情况下,您可能希望Type<T> + U
始终返回Type<T>
。在这种情况下,您需要确保编译器无法确定要转换为的Type<U>
,无论是否支持转换。
@dyp评论部分发布,如何使用帮助程序模板实现此目的。除了不同的名称外,这基本上是:
template <typename T>
struct identity { typedef T type; };
template <typename T>
Type<T> operator+(const Type<T>& type, typename identity<T>::type val) { ... }
这样做的原因是因为编译器不能也不允许弄清楚使用哪个T
来制作identity<T>::type
是int
:你可以在某个地方对identity
进行一些专业化,也可以identity<haha>::type
int
。因此,只有type
用于确定T
。
它有效,但在这种特殊情况下,我认为更简单的方法是将operator+
作为成员函数。成员函数中的隐藏this
参数尚未转换为其他类型的参数。
template<typename T>
struct Type
{
T value;
Type operator+(T val) { ... }
};
注意:如果您还想支持T + Type<T>
添加,则不能使用完全相同的方法:不能为此使用成员函数。但是,如果您已经将这一个运算符作为成员函数,并且如果加法是可交换的,则可以使用非成员operator+
进行仅交换操作数的相反转换。@dyp已经指出了一种使用两个模板参数的替代方法,如果与此处的交换结合使用,该方法效果很好:
template <typename T, typename U>
auto operator+(T val, const Type<U>& type) -> decltype(type.operator+(val)) {
return type.operator+(val);
}
现在,如果你写int + Type<float>
,operator+<int, float>
被实例化和调用,然后最终调用Type<float>.operator+(float)
。所以val
仍然被转换为float
.
(编写type.operator+(val)
而不是type + val
的原因是,否则无效添加Type<T> + Type<U>
将被交换到Type<U> + Type<T>
,后者会再次交换回Type<T> + Type<U>
,直到编译器达到其内部限制甚至可能崩溃。
编译器没有关于如何在用户类型和标准类型之间使用运算符的直接要求: 类型是用户类型。
Type<float> + int has no standard rules defined on the priority of casts.
它应该将 val int 提升为浮点数还是将类型类型提升为其他内容。编译器不知道类型
要解决此问题:
template<typename T, typename U>
Type<T> operator+(const Type<T>& type, U val)
{
// Type<T> type; also do not ovewrite the parameter
type.value += val; // here it knows that type.value is float
// standard rules for float + int
return type;
}
举个例子,为什么编译器决定将什么提升到什么太复杂了,你的类型可能是:
template<typename T>
struct Type
{
T key;
int value;
};
template<typename T>
Type<T> operator+(const Type<T>& type, T val)
{
type.value += val;
return type;
}
如果不分析类型的定义和运算符+的实现,编译器就不知道你的期望是什么,并且做这个分析是非常复杂的。
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- 无法转换类型 C++
- 如何将向量中的可变参数转换为参数的持有者?
- MSVC 错误:4 个重载中的任何一个都无法转换所有参数类型
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- C++stoi:这两个重载都无法转换所有参数类型
- 包含可变参数包的第一个可转换类型的别名的结构
- 我可以将C 17 Capture lambda ConstexPR转换操作符的结果用作函数指针模板非类型参数吗?
- 为什么指针类型强制转换不适用于模板非类型参数
- 3个重载都无法转换所有参数类型(在MFC/C++项目中)
- 转换和模板类型参数
- 错误 C2665:'cv::fillPoly':2 个重载都无法转换所有参数类型
- 生成错误:12 个重载中没有一个可以转换所有参数类型
- 在没有constexpr的模板非类型参数处进行类型转换
- Visual C++错误C2665:3个重载都无法转换所有参数类型
- 为什么模板类型参数不能隐式强制转换?
- 显式转换模板非类型参数时出错
- C2665:'QObject::connect':3 个重载都无法转换所有参数类型
- C++ 3 个重载中没有一个可以转换所有参数类型 第 39 行 1