Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous multiple inheritance of template classes

I've got a real situation which can be summarized in the following example:

template< typename ListenerType >
struct Notifier
{
    void add_listener( ListenerType& ){}
};

struct TimeListener{ };
struct SpaceListener{ };

struct A : public Notifier< TimeListener >
         , public Notifier< SpaceListener >
{

};

struct B : TimeListener{ };

int main()
{
    A a;
    B b;

    a.add_listener( b );    // why is ambiguous?

    return 0;
}

Why is not obvious to the compiler that B is a TimeListener, and therefore the only possible overload resolution is Notifier< TimeListener >::add_listener( TimeListener& ) ?

like image 222
nyarlathotep108 Avatar asked Mar 08 '16 17:03

nyarlathotep108


People also ask

How can we resolve ambiguity in multiple inheritance?

Ambiguity in inheritance can be defined as when one class is derived for two or more base classes then there are chances that the base classes have functions with the same name. So it will confuse derived class to choose from similar name functions. To solve this ambiguity scope resolution operator is used “::”.

What is multiple inheritance ambiguity?

Inheritance Ambiguity in C++ In multiple inheritances, when one class is derived from two or more base classes then there may be a possibility that the base classes have functions with the same name, and the derived class may not have functions with that name as those of its base classes.

Can you inherit template class?

It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

Why is ambiguity in multiple inheritance?

Ambiguity in Multiple Inheritance It's because compiler doesn't know which function to call. For example, class base1 { public: void someFunction( ) {....} }; class base2 { void someFunction( ) {....} }; class derived : public base1, public base2 {}; int main() { derived obj; obj.


1 Answers

The lookup rules for member names say that your code is ambiguous, because the name is found in two base classes and therefore the lookup set is invalid. You don't need to be familiar with all the details of lookup sets and merging; the important detail is that both base classes are checked and the name add_listener is found in both, which creates an ambiguity.

The easy fix is to bring those base class names into A with using-declarations. This means that both versions of add_listener are looked up in A, rather than in the base classes, so there is no merge ambiguity:

struct A : public Notifier< TimeListener >
         , public Notifier< SpaceListener >
{
    using Notifier<TimeListener>::add_listener;
    using Notifier<SpaceListener>::add_listener;
   //plus any more base classes
};

Live Demo

like image 102
TartanLlama Avatar answered Sep 24 '22 07:09

TartanLlama