C ++ Template, Ambiguous Overload

for some reason, I have two classes that implement the "+" operator with templates (I do this because I want all the children of these two classes to be able to use it).

I ended up with very simple code that implements 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 overloading for 'operator +' in 'u + 1' main.cpp: 25: 11: note: candidates: main.cpp: 6: 3: note: operator + ( T &, int) [with T = A] main.cpp: 15: 3: note: statement B + (T &, int) [with T = A]

  • icpc: main.cpp (25): error: more than one "+" operator matches these operands: function template "Operator + (T &, int)" function template "Operator B + (T &, int)" Operand types: A + int A v = u + 1; ^

Though not as ambiguous as v should be of type A, so only the first pattern should work.

Any idea to get around this by supporting two template operators?

Or another idea to have an operator working for all children A and B? That is, 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 the same for B.

Thank,

Tony

EDIT:

Following on from Barry's answer, std :: enable_if does the job. However, it turns out that I had to use exactly two types of names, the method Barry suggested had to be slightly modified to add this capability:

#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 great even if T1 and T2 are different children of A.

+3


source to share


1 answer


Overload resolution is based solely on the signature of the function, which is its name, its cv qualification, and its parameters.

For your first, that is:

operator+(T& lhs, int rhs);

      



And for your second, this is also:

operator+(T& lhs, int rhs);

      



Since they are identical, the compiler cannot distinguish between the two - hence the ambiguity. One way is to move your static assertion to 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 carrier. This will work until you try it with a help T

that comes from both, and then it gets ambiguous again.

Or, depending on what you are actually doing with lhs

, simply:

A operator+(A& lhs, int rhs); // already accepts anything that derives from A

      

+8


source







All Articles