Home >Backend Development >C++ >Why Does Multiple Inheritance Ambiguity Occur in C When Calling a Variadic Template Member Function?

Why Does Multiple Inheritance Ambiguity Occur in C When Calling a Variadic Template Member Function?

Susan Sarandon
Susan SarandonOriginal
2024-10-25 01:50:30907browse

Why Does Multiple Inheritance Ambiguity Occur in C   When Calling a Variadic Template Member Function?

Disambiguating Multiple Inheritance Class Members

Consider the following variadic base class template:

<code class="cpp">template <typename... Types>
class Base {
public:
    template <typename T>
    typename std::enable_if<Contains<T, Types...>::value>::type
    foo() { std::cout << "Base::foo()\n"; }
};

The foo() member can only be called with a template parameter matching one of the types in the Types pack. Now, let's define a derived class with non-overlapping base types:

<code class="cpp">struct Derived : public Base<int, char>, public Base<double, void> {};</code>

Calling Derived().foo() should intuitively resolve to the Base base class. However, the compiler complains of ambiguity.

Why the Compiler Cannot Resolve the Ambiguity:

The merge rules for member lookup [class.member.lookup] state that when the derived class has an empty declaration set (no members), the lookup sets from all base classes must be merged. In our case, the base classes have differing declaration sets, so the merge fails.

Solutions:

To avoid this ambiguity, we can add using declarations to the derived class:

<code class="cpp">struct Derived : public Base<int, char>, public Base<double, void> {
    using Base<int, char>::foo;
    using Base<double, void>::foo;
};</code>

By introducing overloads of foo in the derived class, we effectively bypass the merge rules.

Using a Collector Class:

Alternatively, we can use a template class to aggregate the using declarations from all base classes:

<code class="cpp">template <typename... Bases>
struct BaseCollector;

template <typename Base, typename... Bases>
struct BaseCollector<Base, Bases...> : Base, BaseCollector<Bases...> {
    using Base::foo;
    using BaseCollector<Bases...>::foo;
};

struct Derived : BaseCollector<Base2<int>, Base2<std::string>> {};</code>

This approach is more efficient to compile in C 17, as it allows pack expansion of using declarations.

The above is the detailed content of Why Does Multiple Inheritance Ambiguity Occur in C When Calling a Variadic Template Member Function?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn