Home > Net >  How to resolve ambiguity in template base class template method?
How to resolve ambiguity in template base class template method?

Time:10-20

I am trying to figure out how to resolve an ambiguity problem with function names in base classes.

#include <type_traits>

template <typename T, typename PARENT>
class BaseA 
{
public:
  BaseA(PARENT& p) : _parent(p) {}
  
public:
  template <typename P_ = PARENT>
  auto& parent() {
   if constexpr (std::is_same_v<P_, PARENT>) {
     return _parent;
   } else {
     return _parent.template parent<P_>();
   }
  }
  
private:
  PARENT& _parent;
};

class AbstractBaseB {
  
};

class BaseB : public AbstractBaseB
{
public:
  AbstractBaseB* parent() { return _parent; }
  
private:
 AbstractBaseB* _parent;
};

class Z {
public:
  
  void foo() {}
};

class Y : public BaseA<Y, Z>, public BaseB
{
public:
    Y(Z& z) : BaseA(z) {
        
    }
    
    void foo() {}
};

class X : public BaseA<X, Y>, public BaseB
{
public:
    X(Y& y) : BaseA(y) {
        //This will compile
        BaseA::parent().foo();

        //This will NOT compile
        BaseA::parent<Z>().foo();
    }
};

int main()
{
  Z z;
  Y y(z);
  X x(y);
}

This is a very specific/odd use case, so I have a working example here:

https://cppinsights.io/s/08afbad9

To get it to compile, just comment out line 58. With 58 enabled, this is where I get the ambiguity which is due to line 16:

return _parent.template parent<P_>();

Since _parent is of a different type than this instance of the BaseA template, I can't just do:

return _parent.template BaseA::parent<P_>();

like I did on line 57.

How do I go about fixing this?

For those who ask, the purpose of the templated parent method is to get the "Nth" nested parent without having to do something like parent().parent().parent()

CodePudding user response:

If you want member function (templates) of the same name to be considered from multiple base classes you need to explicitly import them into the derived class scope:

class Y : public BaseA<Y, Z>, public BaseB
{
public:
    /*...*/

    using BaseA::parent;
    using BaseB::parent;
};
  • Related