As Edric pointed out, conversions are not considered during template argument deduction. Here, you have two contexts where the template parameter T can be deduced from the type of the arguments:
template<class T>
v<T> operator+(V<T> const&, V<T> const&);
~~~~~~~~~~~ ~~~~~~~~~~~~
But you try to invoke this function template with a V<float>
on the left-hand side and an S on the right hand side. Template argument deduction results in T=float for the left hand side and you'll get an error for the right hand side because there is no T so that V<T>
equals S<T>
. This qualifies as a template argument deduction failure and the template is simply ignored.
If you want to allow conversions your operator+ shouldn't be a template. There is the following trick: You can define it as an inline friend inside of the class template for V:
template<class T>
class V
{
public:
V();
V(S<T> const&); // <-- note: no explicit keyword here
friend V<T> operator+(V<T> const& lhs, V<T> const& rhs) {
...
}
};
This way, the operator is not a template anymore. So, there is no need for template argument deduction and your invocation should work. The operator is found through ADL (argument dependent lookup) because the left-hand side is a V<float>
. The right-hand side is properly converted to a V<float>
as well.
It is also possible to disable template argument deduction for a specific argument. For example:
template<class T>
struct id {typedef T type;};
template<class T>
T clip(
typename id<T>::type min,
T value,
typename id<T>::type max )
{
if (value<min) value=min;
if (value>max) value=max;
return value;
}
int main() {
double x = 3.14;
double y = clip(1,x,3); // works, T=double
}
Even though the type of the first and last argument is an int, they are not considered during template argument deduction because id<T>::type
is not a so-called *deducible context`. So, T is only deduced according to the second argument, which results in T=double with no contradictions.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…