"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > ## Why Does Multiple Inheritance with Template Base Classes Cause Ambiguity in Member Function Resolution?

## Why Does Multiple Inheritance with Template Base Classes Cause Ambiguity in Member Function Resolution?

Published on 2024-11-08
Browse:282

## Why Does Multiple Inheritance with Template Base Classes Cause Ambiguity in Member Function Resolution?

Ambiguity in Disambiguating Multiple Inheritance

When dealing with multiple inheritance using template base classes, a potential issue arises regarding ambiguous member function resolution. Consider the following scenario:

template 
class Base {
public:
  template 
  typename std::enable_if::value>::type foo() {
    std::cout 

Here, the function foo() is only callable when the template parameter matches one of the types in the Types pack. Now, if a derived class inherits from multiple base classes with non-overlapping type sets, the compiler may encounter ambiguity when resolving the foo() call.

struct Derived: public Base,
                public Base
{};

In this case, the call Derived().foo() would ideally call the foo() member function from Base. However, both GCC and Clang report an ambiguity.

Why the Compiler Cannot Resolve the Ambiguity

The compilation error arises because of the merge rules for member function lookup. According to the C standard, if the member function is not declared in the derived class itself, the lookup process searches the base classes in turn. However, if the declaration sets in the base classes differ, the merge becomes ambiguous.

In the given scenario, the derived class Derived does not declare foo() explicitly, so the compiler must merge the lookup sets from the two base classes. Since the base classes contain different declaration sets for foo(), the merge results in ambiguity.

Solutions

To resolve this ambiguity, one option is to use using declarations in the derived class to explicitly import the desired member functions. However, this requires the user to add these declarations, which can be verbose and impractical for large type lists.

struct Derived: public Base,
                public Base
{
    using Base::foo;
    using Base::foo;
};

Alternatively, one can use a helper class that collects and merges the member functions from all base classes, allowing the derived class to access them directly.

template 
struct BaseCollector : Bases...
{
  using Bases::foo...;
};

struct Derived : BaseCollector, Base>
{};

With this approach, the user does not need to add any additional declarations to resolve the ambiguity. The BaseCollector class effectively merges the declaration sets from all base classes, making the foo() function available to the derived class without ambiguity.

Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3