for some reason I have two classes implementing the operator "+" with templates, (I do that because I want all children of those two classes to be able to use it).
I have come down to a very simple code implementing what I would like to use:
#include <type_traits>
class A{};
template<typename T>
A operator+(T& lhs,int rhs){
static_assert(std::is_base_of<A, T>::value, "T must inherit from A");
A to_return;
return to_return;
}
class B{};
template<typename T>
B operator+(T& lhs,int rhs){
static_assert(std::is_base_of<B, T>::value, "T must inherit from B");
B to_return;
return to_return;
}
int main()
{
A u;
A v = u+1;
}
When compiling, the compiler (g++ or intel) returns the following error :
g++ : main.cpp:25:11: error: ambiguous overload for 'operator+' in 'u + 1' main.cpp:25:11: note: candidates are: main.cpp:6:3: note: A operator+(T&, int) [with T = A] main.cpp:15:3: note: B operator+(T&, int) [with T = A]
icpc : main.cpp(25): error: more than one operator "+" matches these operands: function template "A operator+(T &, int)" function template "B operator+(T &, int)" operand types are: A + int A v = u+1; ^
Although it is not that ambiguous as v should be of type A, so only the first template should work.
Any idea to get around this keeping the two templates operators ?
Or another idea to have an operator working for all children of A and B ?
I.e. for all classes C child of A, I would like to be able to write
A w = u + 1; //where u is of type C.
And same for B.
Thank you,
Tony
Following the answer given by Barry, std::enable_if does the job. However, it turns out that what I needed exactly was to use two typenames, the technique proposed by Barry has to be slightly modified to add this possibility:
#include <type_traits>
#include <iostream>
class A{};
template<typename T1,typename T2 = typename std::enable_if<std::is_base_of<A,T1>::value, A>::type>
A operator+(T1& lhs,T2& rhs){
A to_return;
return to_return;
}
class B{};
template<typename T1,typename T2 = typename std::enable_if<std::is_base_of<B,T1>::value, B>::type>
B operator+(T2& lhs,T2& rhs){
B to_return;
return to_return;
}
int main()
{
A u;
A w = u+u;
}
Then it works fine, even if T1 and T2 are different children of A.
Overload resolution is solely based on the function signature, which is its name, its cv-qualifications, and its parameter types.
For your first one, that is:
operator+(T& lhs, int rhs);
And for your second one, that is also:
operator+(T& lhs, int rhs);
Since those are identical, the compiler can't distinguish between the two - hence the ambiguity. One way around this is to move your static assert into the return type and use SFINAE:
template<typename T>
typename std::enable_if<
std::is_base_of<A, T>::value,
A
>::type
operator+(T& lhs,int rhs){
// stuff
}
And the same for your other operator. This will work until you try it with some T
that derives from both, and then it will become ambiguous again.
Or, depending on what you're actually doing with lhs
, simply:
A operator+(A& lhs, int rhs); // already accepts anything that derives from A
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