Reputation: 2403
I'm trying to do this:
template<class Float>
struct Number {
Float v;
Number(Float iv = 0) : v(iv) {}
};
template<class F>
Number<F> operator+(Number<F> const& a, Number<F> const& b) {
return {a.v + b.v};
}
int main() {
Number<float> y = Number<float>(1) + 2.0f;
std::cout << y.v << "\n";
}
But it doesn't work.
main.cpp:15:38: error: invalid operands to binary expression ('Number<float>' and
'float')
Number<float> y = Number<float>(1) + 2.0f;
~~~~~~~~~~~~~~~~ ^ ~~~~
main.cpp:10:11: note: candidate template ignored: could not match
'Number<type-parameter-0-0>' against 'float'
Number<F> operator+(Number<F> const& a, Number<F> const& b) {
^
And for some reason, this does work:
struct Number {
float v;
Number(float iv = 0) : v(iv) {}
};
Number operator+(Number const& a, Number const& b) {
return {a.v + b.v};
}
int main() {
Number x = Number(1) + 2.0f;
std::cout << x.v << "\n";
}
But I want the template case to work. Basically I'm looking for any kind of workaround to enable me to implement binary operators for Number that will allow one of the args to be something convertible to Number. Preferably c++14 compliant.
Edit: based on Richard's link below, I came up with this which seems to handle the multiple conversions case but still unfortunately requires 3 overloads of each operator:
template<class T>
struct identity {
using type = T;
};
template<class T>
using convertible = typename identity<T>::type;
template<class Float>
struct Param {
Float v;
};
template<class Float>
struct Number {
Float v;
Number(Float iv = 0) : v(iv) {}
Number(Param<Float> iv) : v(iv.v) {}
};
template<class F>
Number<F> operator+(Number<F> const& a, Number<F> const& b) {
return {a.v + b.v};
}
template<class F>
Number<F> operator+(Number<F> const& a, convertible<Number<F>> const& b) {
return {a.v + b.v};
}
template<class F>
Number<F> operator+(convertible<Number<F>> const& a, Number<F> const& b) {
return {a.v + b.v};
}
int main() {
std::cout << (Number<float>{1} + 2).v << "\n";
std::cout << (Number<float>{1} + Param<float>{2}).v << "\n";
std::cout << (Param<float>{1} + Number<float>{2}).v << "\n";
std::cout << (Number<float>{1} + Number<float>{2}).v << "\n";
std::cout << (1 + Number<float>{2}).v << "\n";
}
Upvotes: 2
Views: 57
Reputation: 172934
Implicit conversions won't be considered in template argument deduction.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
So the deduction for template parameter F
failed on the 2nd function parameter b
in Number(1) + 2.0f
, the implicit conversion from float
to Number<float>
won't be considered.
You can add another two overloads as
template<class F, class V>
Number<F> operator+(Number<F> const& a, V const& b) {
return {a.v + Number{b}.v};
}
template<class F, class V>
Number<F> operator+(V const& a, Number<F> const& b) {
return {Number{a}.v + b.v};
}
Upvotes: 2