2010-06-19 4 views
8

Récemment, j'ai beaucoup de problèmes avec typedef et type incomplet lorsque j'ai changé certains conteneurs, les allocateurs dans mon code.typedef et type incomplet

Ce que j'avais déjà

struct foo;//incomplete type. 
typedef std::vector<foo> all_foos; 
typedef all_foos::reference foo_ref; 

Bien que pas complètement pas sûr que les lignes ci-dessus sont légales, mais cela a fonctionné à chaque mise en œuvre je. Quand je pensais que je peux faire le travail avec std::tr1::array, changé les deux lignes ci-dessus avec

typedef std::tr1::array<foo,5> all_foos; 
typedef all_foos::reference foo_ref; 

Ici casse tout, comme le compilateur essaie d'instancier array et échoue foo est un type incomplet. Tout ce dont j'avais besoin est une référence à foo, et pas très intéressé par les 'autres parties' du tableau. foo sera certainement complètement disponible lorsque je créerai un tel tableau.

La même chose est un problème lorsque typedef std::allocator<foo>::pointer foo_ptr a été remplacé par typedef stack_alloc<foo,10>::pointer foo_ptr. où une mise en œuvre stack_alloc est comme

template<typename T,unsigned N> 
struct stack_alloc 
{ 
    typedef T* pointer; 
    typedef std::tr1::aligned_storage<sizeof(T)*N, std::tr1::alignment_of<T>::value> buffer; 
}; 

présumant que, value_type, pointer, reference, iterator etc ne dépend pas de l'intégralité des T, et sachant que la classe ne peut pas être instancier sans type complet, comment ces typedef peut être fait de manière générique indépendamment du conteneur ou de l'allocateur spécifique?

REMARQUE:

  • Juste pour être complet, dans le code « réel » J'utilise une petite mémoire locale avec vector plutôt que de le remplacer par std::array, bien que le problème reste la même. Code
  • stack_alloc le code est loin d'être complet et ne montre que la partie du problème.
  • Je sais que array, sizeof etc. nécessite un type complet disponible. Mais je ne crée pas l'objet de type all_foos avec incomplet foo.
  • Mon assertion est que le pointeur, la référence, etc ne devrait pas dépendre de l'exhaustivité d'un type. Sinon, construire comme struct foo{ foo_ptr p;}; ne peut pas être défini. Bien que probablement foo_ref ne peut être autre chose que foo&, mais foo_ptr peut être. De manière surprenante, l'implémentation de GCC n'a pas de type de pointeur imbriqué pour tr1::array.
  • Sachez surtout ce qui ne peut pas être fait, et intéressé de savoir ce qui peut être fait dans cette situation. Attendant ainsi un bon design en tant que solution.

Répondre

7

Un type doit être complet pour être utilisé dans un conteneur standard, ou le comportement n'est pas défini (§17 .4.3.6/2). Donc, la seule solution standard est de ne pas faire typedef jusqu'à ce que la classe soit définie.

Je ne comprends pas ce que le récipient intermédiaire est pour:

struct foo;//incomplete type. 
typedef foo& foo_ref; 

Dans tous les cas, vous aurez juste à avoir le type complet défini d'abord, vraiment.Pour obtenir un typedef défini dans une classe, cette classe doit être instanciée, ce qui signifie que l'élément entier doit pouvoir utiliser T comme vous le souhaitez.

Par exemple, stack_alloc doit avoir T être un type complet (pour sizeof(T) au travail), sinon la classe ne peut pas être instanciée. Si la classe ne peut pas être instanciée, vous ne pouvez pas en extraire le typedef. Ergo, vous aurez jamais obtenez le typedef Si T est incomplète.

+0

Le conteneur est où foo sera stocké. struct foo; typedef std :: vector > all_foos; typedef all_foos :: pointeur foo_ptr; struct bar {foo_ptr p;}; struct foo {std :: vecteur barres; } all_foos l'instance; cela a-t-il du sens? Si je définis la structure bar {foo * p; } Cela peut ne pas fonctionner car l'alloc peut avoir un pointeur différent de foo * .typedef foo & foo_ref; est ok car aucune autre référence ne peut être définie. – abir

+0

@abir: Je ne peux pas vraiment penser à un exemple où le type de pointeur changerait. Dans tous les cas, si vous voulez vraiment obtenir ces typedefs, il vous suffit d'inclure la définition complète de 'foo'. Pas d'autre chemin. – GManNickG

2

Compiller ne connaît pas la taille du type incomplet, il ne peut donc pas l'instancier ni lui allouer de la mémoire. Avoir un pointeur sur l'objet (comme typedef std::tr1::array<foo*, 5> all_foos;) au lieu de l'instance de l'objet lui-même résout ce problème.