Maison  >  Article  >  développement back-end  >  Pourquoi une ambiguïté d’héritage multiple se produit-elle en C lors de l’appel d’une fonction membre de modèle variadique ?

Pourquoi une ambiguïté d’héritage multiple se produit-elle en C lors de l’appel d’une fonction membre de modèle variadique ?

Susan Sarandon
Susan Sarandonoriginal
2024-10-25 01:50:30830parcourir

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

Désambiguïser plusieurs membres de la classe d'héritage

Considérez le modèle de classe de base variadique suivant :

<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"; }
};

Le foo() member ne peut être appelé qu'avec un paramètre de modèle correspondant à l'un des types du pack Types. Maintenant, définissons une classe dérivée avec des types de base qui ne se chevauchent pas :

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

L'appel de Derived().foo() devrait intuitivement se résoudre en Base classe de base. Cependant, le compilateur se plaint d'ambiguïté.

Pourquoi le compilateur ne peut pas résoudre l'ambiguïté :

Les règles de fusion pour la recherche de membres [class.member.lookup] indiquent que lorsque la classe dérivée a un ensemble de déclarations vide (aucun membre), les ensembles de recherches de toutes les classes de base doivent être fusionnés. Dans notre cas, les classes de base ont des ensembles de déclarations différents, donc la fusion échoue.

Solutions :

Pour éviter cette ambiguïté, nous pouvons ajouter des déclarations using aux classes dérivées 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>

En introduisant des surcharges de foo dans la classe dérivée, nous contournons efficacement les règles de fusion.

Utilisation d'une classe Collector :

Alternativement, nous pouvons utiliser une classe modèle pour regrouper les déclarations using de toutes les classes de base :

<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>

Cette approche est plus efficace à compiler en C 17, car elle permet l'expansion du pack de déclarations using.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn