Problème dans GCC / C ++ 17 avec la classe de modèles de modèles

10

Considérez les 2 surcharges suivantes

template<typename T>
bool test() {
    return true;
}

template<template<typename ...> class T>
bool test() {
    return false;
}

Le 1er fonctionne pour les classes régulières, tandis que le 2ème fonctionne pour les modèles qui ne sont pas instanciés. Par exemple:

    std::cout<<test<int>()<<std::endl; <-- this yields 1
    std::cout<<test<std::list>()<<std::endl; <--this yields 0

Considérez maintenant la fonction de modèle suivante:

template<typename U>
bool templfun(){
    struct A{
        bool f(){
            return test<A>(); // <-- this gives an error
        }
    };
    return test<A>();  // <-- this is ok
}

Dans GCC, il donne une erreur pour la résolution de surcharge ambiguë, tandis que Clang compile. Fait intéressant, le deuxième appel à test () ne produit pas d'erreurs (même dans GCC). De plus, si je retire la template<typename U>chose au-dessus de templfun, gcc cesse de se plaindre.

Est-ce un bug avec GCC ou est-ce du code illégal?

Marieddu
la source

Réponses:

4

GCC a tort; struct Aest une entité basée sur un modèle mais clairement pas un modèle (car elle ne commence pas par un templatemot - clé), il n'y a donc pas d'ambiguïté.

Pour confirmer, nous pouvons renommer le paramètre type pour voir que G ++ tente d'utiliser la surcharge template-template.

template <typename X>
bool test() {
    return true;
}

template <template <typename...> class Y>
bool test() {
    return false;
}

template <typename U>
bool templfun() {
    struct A {
        bool f() {
            return test<A>(); // <-- this gives an error
        }
    };
    return test<A>(); // <-- this is ok
}

bool run() {
    return templfun<int>();
}

Sortie G ++: ( lien vers godbolt )

<source>:15:27: error: call of overloaded 'test<templfun() [with U = int]::A>()' is ambiguous
   15 |             return test<A>(); // <-- this gives an error
      |                    ~~~~~~~^~

<source>:2:6: note: candidate: 'bool test() [with X = templfun() [with U = int]::A]'
    2 | bool test() {
      |      ^~~~

<source>:7:6: note: candidate: 'bool test() [with Y = templfun()::A]'
    7 | bool test() {
      |      ^~~~

Il candidate: 'bool test() [with Y = templfun()::A]'est clair que " " est faux.

Notez que les types locaux n'étaient pas autorisés comme arguments de modèle avant C ++ 11 (voir C ++ 03 § 14.3.1.2), ce qui pourrait expliquer la complexité de l'implémentation G ++.

rustyx
la source