2010-09-15 6 views
2

Je voudrais passer des valeurs d'octets numériques via une liste d'initialisation un modèle variadique dans un tableau. Est-ce possible?listes char et initialiseur

template < int N > struct a { 
    char s[N]; 
    template < typename ... A > 
    a (A ... _a) : s {_a...} {} 
}; 

int main() { 
    // g++-4.5: error: narrowing conversion of »_a#0« from »int« to »char« inside { } 
    a <3> x { 1, 2, 3 }; 
} 

Ce que je peux penser est

  • à utiliser la représentation octal, '\ 001', etc., ou
  • de jeter chaque valeur unique.

Mais les deux ne sont pas satisfaisants.

+0

Pourquoi est-il un problème de jeter les valeurs? Si vous voulez faire attention au type de distribution, utilisez 'boost :: numeric_cast' et autorisez spécifiquement les conversions plus étroites. D'une façon ou d'une autre, vous réduisez ces arguments. – Potatoswatter

+0

Si vous ne fournissez aucun constructeur, vous pourrez utiliser l'initialisation de l'accolade pour les agrégats. – sellibitze

Répondre

0

REMARQUE: Tout cela n'est pas nécessaire, sauf si vous avez ajouté des fonctionnalités à la classe, donc ce n'est plus un agrégat. (Par exemple, d'autres constructeurs, des membres privés, une classe de base, etc.) La manière immédiate de corriger le code dans la question est simplement de supprimer le constructeur. Alors, supposons qu'il y a quelque chose de plus.

J'ai vu des gens essayer de faire des choses comme ça. Il semble laid, traitant de la sémantique de conversion et essayant de recréer artificiellement la fonctionnalité d'un appel de fonction habituel.

Voici une stratégie pour créer une classe de tableau qui a simplement le bon constructeur en premier lieu.

L'aliasing de modèle mettrait la cerise sur le gâteau en cachant la laideur ::type, mais ce n'est pas encore dans GCC.

template< typename ... NT > 
struct var_ctor_array { 
    enum { size_e = 0 }; // only used for zero size case 
}; 

template< typename T, typename ... NT > 
struct var_ctor_array< T, NT ... > { 
    enum { size_e = 1 + sizeof...(NT) }; 

    T st[ size_e ]; 

    var_ctor_array(T elem0, NT ... elemN) 
     : st { elem0, elemN ... } {} 
}; 

template< typename T, size_t N, typename ... NT > 
struct gen_var_ctor_array { 
    typedef typename gen_var_ctor_array< T, N-1, T, NT ... >::type type; 
}; 

template< typename T, typename ... NT > 
struct gen_var_ctor_array< T, 0, NT ... > { 
    typedef var_ctor_array< NT ... > type; 
}; 

int main() { // usage 
    gen_var_ctor_array< char, 5 >::type five(1, 2, 3, 4, 5); 
} 
+0

Super idée, je vais utiliser les classes. g ++ ne compilera pas sans le cas particulier de 'size_e == 0' en raison d'un bug. Maintenant, serait-il possible d'avoir 'T()' comme valeur par défaut pour chaque paramètre? – Thomas

+0

@Thomas: En essayant, "le paquet de paramètres 'elemN' ne peut pas avoir un argument par défaut". Cependant, cette fonctionnalité pourrait être piratée en utilisant des constructeurs héritants, qui ne sont pas dans GCC 4.5. – Potatoswatter

+0

Qu'est-ce qui déclenche ce bug?'gen_var_ctor_array < char, 0 > :: type zero;' fonctionne ... – Potatoswatter

0

Vous n'utilisez pas réellement les listes d'initialisation. Le constructeur reçoit un variadic template et vous initialisez x avec uniform initialization.

Le seul problème est que je ne sais pas d'une façon élégante de l'initialisation d'un tableau avec un initializer_list, AFAIK std::array devrait avoir un constructeur qui accepte initializer_list mais il ne semble pas être pris en charge par g ++ encore.

#include <utility> 
template < int N > struct a { 
    char s[N]; 

    a (std::initializer_list<char> list) { 
     if (N != list.size()) 
      throw "list wrong size"; 

     int i = 0; 
     const char* p = list.begin(); 
     while(p != list.end()) 
      s[i++] = *p++; 
    } 
}; 
+0

Vous avez absolument raison, les modèles variés sont ce que je voulais écrire. Les listes d'initialisation ne sont peut-être pas aussi efficaces pour l'initialisation d'un tableau. – Thomas

+0

'array' n'a pas besoin de supporter' initializer_list' car il fait déjà la même chose en C++ 03 en étant un agrégat. Rien n'est plus efficace que cela, car cela équivaut à une initialisation de membre sur place. – Potatoswatter

0

Vous n'avez pas besoin de code compliqué

template < int N > struct a { 
    char s[N]; 
    template < typename ... A > 
    a (A ... _a) : s {static_cast<char>(_a)...} {} 
}; 
Questions connexes