The*_*ang 0 c++ templates types type-conversion
鉴于此代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
我在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
Run Code Online (Sandbox Code Playgroud)
我认为它只会将int提升为浮点数,但显然它不想这样做.有办法解决这个问题吗?
小智 6
问题是编译器无法确定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) { ... }
Run Code Online (Sandbox Code Playgroud)
这样做的原因是因为编译器不能也不允许弄清楚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) { ... }
};
Run Code Online (Sandbox Code Playgroud)
注意:如果您还想支持T + Type<T>添加,那么您不能使用这种完全相同的方法:您不能使用成员函数.但是如果你已经将这一个运算符作为成员函数,并且如果add是可交换的,则可以使用非成员operator+进行相反的转换,只需交换操作数.@dyp已经指出了一种使用两个模板参数的替代方法,如果与此处的交换相结合,则效果很好:
template <typename T, typename U>
auto operator+(T val, const Type<U>& type) -> decltype(type.operator+(val)) {
return type.operator+(val);
}
Run Code Online (Sandbox Code Playgroud)
现在,如果你写int + Type<float>,operator+<int, float>得到实例化和调用,然后最终调用Type<float>.operator+(float).所以val仍然转换为float.
(写入的原因type.operator+(val)而不是type + val因为否则Type<T> + Type<U>会交换无效的gets Type<U> + Type<T>,这会Type<T> + Type<U>再次交换回来,直到编译器达到其内部限制甚至可能崩溃.)