问题
Consider the following classes, where the first is templated. Both are meant to hold a numeric value.
template<typename T>
struct foo
{
foo(T val) : val{ val } {}
T val;
};
struct bar
{
bar(double val) : val{ val } {}
double val;
};
I want to define a way to add these classes together to get a new one with a different value.
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);
}
When I use these operators with implicit conversion, the operator using object of type foo
doesn't use the implicit conversion on the double value to apply my overloaded operator, even though it can do it for the non-template class. The result is that there is no operator matching the types in that expression.
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;
}
Does the operator have to be explicitly instantiated first? If so, a) how does that look like, and b) why isn't the instantiation done implicitly, if it can be done when initializing an object of type foo<double>
?
If the standard doesn't support any sort of resolution without explicitly casting 1.0
to a value of type foo<double>
, I presume the only other possibility is defining operator overloads for each type I want to use like that (for both lhs and rhs)?
回答1:
The thing you have to remember about templates is that they will not do a conversion for you. All they do is try and figure out the types things are, and if that jives with template parameters, then it will stamp out the function and call it.
In you case when you do
foo_value + 1.0
the compiler goes okay, lets see if we have any operator +
that will work for this. It finds
template<typename T>
foo<T> operator+(foo<T> a, foo<T> b)
{
return foo<T>(a.val + b.val);
}
and then it tries to figure out what T
is so it can stamp out a concrete function. It looks at foo_value
, sees it is a foo<double>
so it says for the first parameter T
needs to be a double
. Then it looks at 1.0
and goes okay, I have a double
and that is when you run into a problem. The compiler can't deduce what T
should be for b
because it expects a foo<some_type>
, but got a double
instead. Because it can't deduce a type, your code fails to compile.
In order to get the behavior you want you would need to add
template<typename T>
foo<T> operator+(foo<T> a, T b)
{
return foo<T>(a.val + b);
}
Which lets you add a T
to a foo<T>
, or better yet
template<typename T, typename U>
foo<T> operator+(foo<T> a, U b)
{
return foo<T>(a.val + b);
}
Which lets you add anything to a foo<T>
(foo<double> + int
for instance where the first version would not allow that)
来源:https://stackoverflow.com/questions/56262451/binary-operator-for-template-class-doesnt-resolve-implicit-conversion