2010-06-19 13 views
8

Recientemente estoy teniendo muchos problemas con typedef y tipo incompleto cuando cambié ciertos contenedores, asignador en mi código.typedef e incompleto tipo

Lo que tenía previamente

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

Aunque no del todo sin saber si las líneas anteriores son legales, pero esto funcionó en cada aplicación que he usado. Cuando pensé que puedo hacer el trabajo con std::tr1::array, cambiado las dos líneas anteriores con

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

Aquí todo se rompe, como el compilador intenta crear una instancia de array y no como es foo tipo incompleto. Lo único que necesitaba es una referencia a foo, y no me interesan mucho las 'otras partes' de la matriz. Foo definitivamente estará completamente disponible cuando creo dicha matriz.

Igual es un problema cuando typedef std::allocator<foo>::pointer foo_ptr ha sido reemplazado por typedef stack_alloc<foo,10>::pointer foo_ptr. donde una implementación stack_alloc es como

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; 
}; 

Suponiendo que, value_type, pointer, reference, iterator etc no depende de la integridad de T, y sabiendo que la clase no se puede crear una instancia sin tipo completo, de la mencionada typedef puede hacerse de manera genérica independientemente de un contenedor o asignador específico?

NOTA:

  • simplemente para la corrección, en código 'real' que utilizo una pequeña memoria local con vector en lugar de reemplazarlo con std::array, aunque el problema sigue siendo igual.
  • stack_alloc código está lejos de completarse, y solo muestra la parte del problema.
  • Sé que array, sizeof, etc. necesita el tipo completo disponible. Pero NO estoy creando objeto del tipo all_foos con foo incompleto.
  • Mi afirmación es que el puntero, la referencia, etc. no deberían depender de la integridad de un tipo. De lo contrario, construir como struct foo{ foo_ptr p;}; no se puede definir. Aunque probablemente foo_ref no puede ser otra cosa que foo&, pero foo_ptr puede ser. Sorprendentemente, la implementación de GCC no tiene el tipo de puntero anidado para tr1::array.
  • Conozca principalmente lo que no se puede hacer, e interesado en saber qué se puede hacer en esta situación. Así que esperamos un buen diseño como solución.

Respuesta

7

Un tipo debe estar completo para usarse en un contenedor estándar, o el comportamiento no está definido (§17 .4.3.6/2). Entonces, la única solución estándar es no hacer ese typedef hasta que se defina la clase.

que no entiendo lo que el contenedor intermedio es para:

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

En cualquier caso, usted sólo tiene que tener el tipo definido por primera vez completa, la verdad.Para obtener un typedef definido en una clase, se debe instanciar esa clase , lo que significa que todo debe poder usar T según lo desee.

Por ejemplo, stack_alloc debe tener T ser un tipo completo (para que sizeof(T) funcione), de lo contrario no se puede crear una instancia de la clase. Si no se puede crear una instancia de la clase, no puede obtener el typedef. Ergo, usted nunca obtenga el typedef si T está incompleto.

+0

El contenedor es donde foo se almacenará. struct foo; typedef std :: vector > all_foos; typedef all_foos :: puntero foo_ptr; struct bar {foo_ptr p;}; struct foo {std :: vector barras; }; all_foos the_instance; tiene sentido? Si defino struct bar {foo * p; }; Es posible que NO funcione ya que el alloc puede tener un puntero diferente que foo * .typedef foo & foo_ref; está bien ya que no se puede definir ninguna referencia de otra manera. – abir

+0

@abir: Realmente no puedo pensar en un ejemplo donde el tipo de puntero cambiaría. En cualquier caso, si realmente quieres obtener esos typedefs, solo tendrás que incluir la definición completa de 'foo'. Ninguna otra manera. – GManNickG

2

Compiller no conoce el tamaño del tipo incompleto, por lo tanto, no puede crear una instancia ni asignarle memoria. Tener un puntero a objeto (como typedef std::tr1::array<foo*, 5> all_foos;) en lugar de la instancia del objeto mismo resuelve este problema.

Cuestiones relacionadas