41 votes

Toutes les versions de GCC ont des difficultés avec un modèle qui a le type par défaut dans une définition

J'ai perdu de nombreuses heures à localiser un problème avec gcc. J'ai voulu tester notre base de code avec un autre compilateur de regarder pour plus de mises en garde que Clang peut-être manqué. J'ai été choqué de voir que pratiquement la moitié de la projet arrêté pour compiler en raison de l'échec de l'argument de modèle de déduction. J'ai essayé ici de muets mon cas, jusqu'à la plus simple morceau de code.

#include <type_traits>

struct Foo
{ };

// This is a template function declaration, where second template argument declared without a default
template <typename T, typename>
void foo(const Foo & foo, T t);

// This is a template function definition; second template argument now has a default declared
template <typename T, typename = typename std::enable_if<1>::type>
void foo(const Foo & foo, T t)
{
}

int main(int argc, char ** argv)
{
    foo(Foo{}, 1);
    return 0;
}

Ignorer un 1 dans la std::enable_if<1>. Évidemment, c'est une valeur constante, simplement pour ne pas compliquer les choses quand il n'a pas d'importance.

Ce morceau de code compile[1] avec clang (3.4 à 4.0), cpi (16, 17), Visual C++ (19.00.23506). Fondamentalement, je ne pouvais pas trouver n'importe quel autre c++11 compilateur qui, à l'exception de gcc (de 4,8 à travers 7.1), ne compile pas ce morceau de code.

La question est de savoir qui a raison et qui a tort ici? Ne gcc se comportent conformément à la norme?

Évidemment, ce n'est pas un problème critique. Je peux facilement passer d' std::enable_if à la déclaration. La seule victime serait l'esthétique. Mais il est agréable d'être en mesure de cacher un vilain 100 caractères std::enable_if morceau de code, qui n'est pas immédiatement pertinents pour l'utilisateur de la fonction de la bibliothèque, dans la mise en œuvre.


Live exemple sur godbolt.org.

34voto

GreenScape Points 1136

Ce que dit la norme ([1] , page 350):

L'ensemble du modèle par défaut des arguments disponibles pour une utilisation avec un modèle de déclaration ou de définition est obtenue par fusion de la valeur par défaut les arguments de la définition (si dans le champ d'application) et toutes les déclarations dans la portée de la même manière par défaut arguments de la fonction sont (8.3.6). [ Exemple:

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;

fin de l'exemple ]

Si GCC est le problème ici. Il ignore modèle par défaut arguments dans les déclarations.

Pas toutes les déclarations, que la fonction de modèle de déclarations. Modèle de classe déclarations sont d'accord:

#include <type_traits>

template <typename T, typename>
struct Foo;

template <typename T, typename = typename std::enable_if<1>::type>
struct Foo
{
    T t;
};

int main()
{
    Foo<int> foo;
    return 0;
}

Live exemple sur godbolt.org


C'est probablement en raison de la nature de la façon dont les non-arguments par défaut sont déduites. Dans le modèle de fonction, ils sont déduits à partir des arguments de la fonction. Dans le modèle de classe que nous avons à spécifier de façon explicite.

De toute façon, j'ai créé un rapport de bug.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X