37 votes

Erreur GCC avec modèles variadiques: "Désolé, aucune implémentation: impossible de développer" Identifiant ... "dans une liste d'arguments de longueur fixe"

Tout en faisant variadic template de la programmation en C++11 sur GCC, une fois dans un certain temps, j'obtiens un message d'erreur qui dit "Désolé, non mises en œuvre: ne peut pas développer Identifiant..." dans une longueur fixe arugment liste." Si je supprime les "..." dans le code, puis je reçois un autre message d'erreur: "erreur: paramètre packs pas étendu avec des '...'".

Donc, si j'ai les "..." dans la, CGC appelle qu'une erreur, et si j'enlève les "...", que GCC appelle une erreur de trop.

Le seul moyen que j'ai été en mesure de traiter cette question est de réécrire complètement le modèle metaprogram à partir de zéro en utilisant une approche différente, et (avec de la chance) j'ai fini par venir avec un code qui n'est pas la cause de l'erreur. Mais je voudrais vraiment savoir ce que je faisais mal. En dépit de Googler pour elle et malgré beaucoup d'expérimentation, je ne peux pas cerner ce que c'est que je suis en train de faire différemment entre les variadic template de code qui ne produisent cette erreur, et le code qui n'ont pas l'erreur.

Le libellé du message d'erreur semble indiquer que le code devrait fonctionner selon le standard C++11, mais que GCC ne le supporte pas encore. Ou c'est peut-être un bug du compilateur?

Voici un code qui génère l'erreur. Note: je n'ai pas besoin de vous pour écrire une mise en œuvre correcte pour moi, mais juste pour souligner ce qui est sur mon code qui est à l'origine de cette erreur

// Used as a container for a set of types.
template <typename... Types> struct TypePack
{
    // Given a TypePack<T1, T2, T3> and T=T4, returns TypePack<T1, T2, T3, T4>
    template <typename T>
    struct Add
    {
        typedef TypePack<Types..., T> type;
    };
};

// Takes the set (First, Others...) and, while N > 0, adds (First) to TPack.
// TPack is a TypePack containing between 0 and N-1 types.
template <int N, typename TPack, typename First, typename... Others>
struct TypePackFirstN
{
    // sorry, unimplemented: cannot expand ‘Others ...' into a fixed-length argument list
    typedef typename TypePackFirstN<N-1, typename TPack::template Add<First>::type, Others...>::type type;
};

// The stop condition for TypePackFirstN:  when N is 0, return the TypePack that has been built up.
template <typename TPack, typename... Others>
struct TypePackFirstN<0, TPack, Others...> //sorry, unimplemented: cannot expand ‘Others ...' into a fixed-length argument list
{
    typedef TPack type;
};

EDIT: j'ai remarqué que, bien que partielle de l'instanciation d'un modèle qui ressemble à n'encourir l'erreur:

template <typename... T>
struct SomeStruct<1, 2, 3, T...> {};

La réécriture comme cela ne produit pas une erreur:

template <typename... T>
struct SomeStruct<1, 2, 3, TypePack<T...>> {};

Il semble que vous pouvez déclarer les paramètres partiel des spécialisations à variadic; c'est à dire cette ligne est OK:

template <typename... T>

Mais vous ne pouvez pas réellement utiliser ces paramètre packs dans la spécialisation, c'est à dire cette partie n'est pas OK:

SomeStruct<1, 2, 3, T...>

Le fait que vous pouvez le faire fonctionner, si vous l'envelopper le paquet à un autre type, c'est à dire comme ceci:

SomeStruct<1, 2, 3, TypePack<T...>>

pour moi, implique que la déclaration de la variadic paramètre à une partie du modèle de spécialisation a été un succès, et vous ne pouvez pas l'utiliser directement. Quelqu'un peut-il confirmer cela?

48voto

deft_code Points 19418

Il y a une astuce pour que cela fonctionne avec gcc. La fonctionnalité n'est pas encore complètement implémentée, mais vous pouvez structurer le code pour éviter les sections non implémentées. Développer manuellement un modèle variadique dans une liste de paramètres ne fonctionnera pas. Mais la spécialisation des modèles peut le faire pour vous.

 template< char head, char ... rest >
struct head_broken
{
   static const char value = head;
};

template< char ... all >
struct head_works; // make the compiler hapy

template< char head, char ... rest >
struct head_works<head,rest...> // specialization
{
   static const char value = head;
};

template<char ... all >
struct do_head
{
   static const char head = head_works<all...>::value;
   //Sorry, unimplemented: cannot expand 'all...' into a fixed-length arugment list
   //static const char head = head_broken<all...>::value;
};

int main
{
   std::cout << head_works<'a','b','c','d'>::value << std::endl;
   std::cout << head_broken<'a','b','c','d'>::value << std::endl;
   std::cout << do_head<'a','b','c','d'>::head << std::endl;
}
 

J'ai testé cela avec gcc 4.4.1

3voto

Autant je comprends l'erreur est signalée, car le compilateur voit la déclaration de la classe de modèle en tant que classe avec au moins 3 arguments suivie par l'option. Depuis que vous essayez de consulter avec 2 arguments, suivie par l'expansion de la liste, il devient confus et les enjeux de cette erreur. Afin de faire compiler correctement, vous juste devez d'abord déclarer le modèle comme ceci:

template <int N, typename TPack, typename... Others>
struct TypePackFirstN;

Et après que la récurrence de l'étape de définition doit être reformulé comme un modèle de spécialisation. (cela fait l'affaire avec gcc 4.5.0 20100404).

// Takes the set (First, Others...) and, while N > 0, adds (First) to TPack.
// TPack is a TypePack containing between 0 and N-1 types.
template <int N, typename TPack, typename First, typename... Others>
struct TypePackFirstN<N, TPack, First, Others...>
{
    // Error "sorry, unimplemented: cannot expand ‘Others ...' into a fixed-length argument list" should be now gone
    typedef typename TypePackFirstN<N-1, typename TPack::template Add<First>::type, Others...>::type type;
};

// The stop condition for TypePackFirstN:  when N is 0, return the TypePack that has been built up.
template <typename TPack, typename... Others>
struct TypePackFirstN<0, TPack, Others...>         // Error "sorry, unimplemented: cannot expand ‘Others ...' into a fixed-length argument list" should be now gone
{
    typedef TPack type;
};

2voto

LiraNuna Points 21565

Quelle version de GCC utilisez-vous? Selon cette GCC page de statut, GCC 4.4 doit être pris en charge.

Test avec GCC 4.4.2, j'obtiens une erreur semblable.

Le libellé du message d'erreur semble dire que le code devrait fonctionner selon le C++0x standard, mais qui GCC ne le supporte pas encore. Ou peut-être c'est un bug du compilateur?

C'est correct, GCC comprend le code, mais ne peut pas encore cracher GIMPLE pour elle.

Comme les causes de l'erreur, c'est l'extension de la variable de modèle de liste à un autre modèle de la liste de variables.

1voto

firebush Points 540

deft_code réponse est bonne. Je poste ceci juste dans ce cas il est utile de voir un side-by-side de comparaison de cassé rapport à code fixe.

Je vais prendre l'exemple de code à partir de la question suivante: quelqu'un a posté qui a été dupliqué à celui-ci et est maintenant fermé: Est il une bonne solution pour GCC est "désolé, non mises en œuvre: ne peut pas développer la PROCHAINE ... "dans une longueur fixe de la liste d'arguments d'erreur"?

#include <iostream>

template <int FIRST, int... NEXT>
struct Test {
    static const int VALUE = FIRST + Test<NEXT...>::VALUE;
};

template <int FIRST>
struct Test<FIRST> {
    static const int VALUE = FIRST;
};

int main() {
    std::cout << Test<1, 2, 3>::VALUE << std::endl; // print "6"
    return 0;
}

Ce, au moment de la compilation, donne:

g++ -std=c++11 -o test test.cc
test.cc:5:50: sorry, unimplemented: cannot expand âNEXT ...â into a fixed-length argument list

Mais cela fonctionne (j'ai ajouté des commentaires où le code a été changé):

#include <iostream>

template <int ... ALL> // Adeed
struct Test;           // Added

template <int FIRST, int... NEXT>
struct Test<FIRST, NEXT...> { // Note: specialized with <FIRST, NEXT...>
    static const int VALUE = FIRST + Test<NEXT...>::VALUE;
};

template <int FIRST>
struct Test<FIRST> {
    static const int VALUE = FIRST;
};

int main() {
    std::cout << Test<1, 2, 3>::VALUE << std::endl; // print "6"
    return 0;
}

Note ce qui a été fait dans ce triple changement de ligne marquée par les commentaires: ce qui était à l'origine le premier modèle a été faite spécialisée modèle de la nouvelle variadic template.

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