I have a struct template A<x>
and a +
operator with int
.
#include <iostream>
template<int x>
struct A{
int a;
};
template<int x>
int operator+(A<x> a, int b){
return a.a+b;
}
I created a struct template B<x>
, which is convertible to A<x>
.
template<int x>
struct B{
int b=3;
operator A<x>(){
return {b+10};
}
};
Now I want B<x>
to be converted to A<x>
when calling B<x> + int
.
int main(){
std::cout<<(A<12>{9}+10)<<std::endl;//OK
std::cout<<(B<12>{9}+10)<<std::endl;//Error
return 0;
}
I read Implicit conversion when overloading operators for template classes and wrote
template<int x>
struct B{
int b=3;
operator A<x>(){
return {b+10};
}
friend int operator+(A<x> a, int b);
};
, but it didn't work because the declared friend int operator+(A<x> a, int b)
does not match template<int x> int operator+(A<x> a, int b)
.
I read C++ - How to declare a function template friend for a class template and made friend declaration template, but it didn't work because the template parameter couldn't be deduced.
Of course I could write operator+ for both A and B, but I have dozens of operators and I don't want to do it.
What is the correct way to do this?
There are two types of user-defined conversions: Conversion constructors and conversion functions.
An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.
For more information, see Standard Conversions. User-defined conversions perform conversions between user-defined types, or between user-defined types and built-in types. You can implement them as Conversion constructors or as Conversion functions.
Implicit type conversion also known as automatic type conversion is carried out by the compiler without the need for a user-initiated action. It takes place when an expression of more than one data type is present which in such an instance type conversion takes place to avoid data loss.
Looking at the two ways to make a non-member operator+
for A
, we can either make it a function template:
template <int x>
int operator+(A<x>, int);
which won't match B<x>
because we're just doing template deduction, which doesn't allow for conversions.
Or, we can make it a friend non-template:
template <int x>
struct A {
friend int operator+(A a, int );
};
which also won't match B<x>
because name lookup won't consider that function. Unless, that is, we tell it to:
template <int x>
struct B {
friend int operator+(A<x>, int ); // NB: not a template
};
Now, our original non-template operator+
will be considered, the conversion will be performed as desired, and your code prints 29.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With