请考虑以下类,其中第一个是模板化的。两者都应保留一个数值。
template<typename T>
struct foo
{
foo(T val) : val{ val } {}
T val;
};
struct bar
{
bar(double val) : val{ val } {}
double val;
};
我想定义一种将这些类加在一起以获得具有不同值的新类的方法。
template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
return foo<T>(a.val + b.val);
}
bar operator+(bar a, bar b)
{
return bar(a.val + b.val);
}
当我将这些运算符用于隐式转换时,使用对象类型foo
的运算符不会对double值使用隐式转换来应用我的重载运算符,即使它可以对非模板类。结果是没有运算符匹配该表达式中的类型。
int main()
{
foo<double> foo_value(11.0);
bar bar_value(11.0);
foo<double> ev1 = foo_value + 1.0; // no operator matches these operands
bar ev2 = bar_value + 1.0;
}
是否必须首先显式实例化运算符?如果是这样,a)看起来如何,b)如果初始化类型为foo<double>
的对象时可以完成实例化,为什么不隐式完成呢?
如果标准在不显式地将1.0
强制转换为类型foo<double>
的值的情况下不支持任何类型的分辨率,则我认为唯一的另一种可能性是为要使用的每种类型定义运算符重载这样(对于lhs和rhs)?
答案 0 :(得分:2)
关于模板,您需要记住的一点是,模板将不为您进行转换。他们所做的只是尝试找出事物的类型,如果这些事物与模板参数匹配,那么它将标记出函数并调用它。
如果您这样做的话
foo_value + 1.0
编译器运行正常,让我们看看是否有任何operator +
可以满足要求。找到
template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
return foo<T>(a.val + b.val);
}
,然后它试图找出T
是什么,以便可以标记出一个具体函数。它看着foo_value
,看到它是一个foo<double>
,因此它说对于第一个参数T
必须是一个double
。然后它看着1.0
并正常,我有一个double
,那就是您遇到问题时。编译器无法推断T
应该是b
是什么,因为它期望foo<some_type>
,但却得到了double
。因为它不能推导类型,所以您的代码无法编译。
为了获得您想要的行为,您需要添加
template<typename T>
foo<T> operator+(foo<T> a, T b)
{
return foo<T>(a.val + b);
}
您可以将T
添加到foo<T>
中,或者更好
template<typename T, typename U>
foo<T> operator+(foo<T> a, U b)
{
return foo<T>(a.val + b);
}
您可以在其中添加任何内容到foo<T>
(例如第一个版本不允许的情况下,foo<double> + int
)