Reputation: 693
I have a template class and a friend operator*
function
StereoSmp<TE> operator* (const StereoSmp<TE>& a, TE b)
I use it with TE=float
but I need to multiply a StereoSmp<float> * double
I think that should be possibile because it should converts double
to float
automatically and works but I get the error:
no match for ‘operator*’ (operand types are ‘StereoSmp<float>’ and ‘__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type {aka double}’) deduced conflicting types for parameter ‘TE’ (‘float’ and ‘double’)
Why it doesn't convert double to float automatically? And what can I do to allow the automatic conversion between types?
Upvotes: 2
Views: 105
Reputation: 283793
Although Yakk's answer is probably the best in this particular scenario, I want to point out that you can prevent this deduction conflict and get your expected result (pass StereoSmp<float>
, deduce TE
as float
) by making the other argument ineligible for use in deduction:
StereoSmp<TE> operator* (const StereoSmp<TE>& a, remove_reference<TE>::type b)
Related reading: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3766.html
Upvotes: 2
Reputation: 20651
Why it doesn't convert double to float automatically? And what can I do to allow the automatic conversion between types?
This isn't a conversion problem, it's a template parameter inference issue. Since the declaration is of the form:
StereoSmp<TE> operator* (const StereoSmp<TE>& a, TE b)
... and the operands are of type StereoSmp<float>
and double
, the C++ inference rules do not work, because they do not take into account that a double
is convertible to a float
. These rules are specified by the language specification; the reason why they don't take potential conversions into account is probably because "it would make deduction very complicated, otherwise". The rules are already complex enough!
You can of course cast your double
parameter to a float
and it will work fine. Also, you could make the operator*
a member function of StereoSmp
, or you could independently parameterise the types of the type parameters:
template <class TE, class U> StereoSmp<TE> operator* (const StereoSmp<TE>& a, U b);
Upvotes: 0
Reputation: 275800
Don't make your friend a template.
template<class TE>
struct StereoSmp {
friend StereoSmp operator* (const StereoSmp& a, TE b) {
return multiply( a, b ); // implement here
}
};
this is a non-template friend to each type instance of the template StereoSmp
. It will consider conversions.
Template functions don't consider conversions, they simply do exact pattern matching. Overload resolution is already insane enough in C++.
Upvotes: 5
Reputation: 40140
template<class U>
StereoSmp<TE> operator* (const StereoSmp<TE>& a, U b);
or if it applies:
StereoSmp<TE> a {/* ... */};
double b = /* ... */;
auto c = a * static_cast<float>(b);
Why it doesn't convert double to float automatically?
Because template deduction happens before possible conversions are taken into consideration. If you call a*b
with a
a StereoSmp<float>
and b
a double
, template substitution will fail before a float
to double
conversion can be considered, and name lookup will continue, until failing short of candidates.
This process is called Template argument deduction.
Upvotes: 3