2012-03-25 13 views
11

que tienen un tipo de datos recursiva como esto:con plantilla tipos de datos recursivas

template<typename T> 
struct SomeType { 
    std::map<T, SomeType<T>> mapping; 
}; 

SomeType<int> foo; 

Esto funciona bien, pero sustituyendo std::map con std::unordered_map da como resultado un error de compilación debido a un tipo incompleto. ¿Estoy (o gcc) cometiendo un error en alguna parte? o es esto solo parte del estándar?

También me gustaría tener el contenedor interno determinado por un parámetro de plantilla (como std::stack y std::queue), pero no puedo encontrar una manera de hacerlo ya que eso requeriría que SomeType ya estuviera definido.

ejemplo incompleto:

template<typename T, typename C = std::map<T, SomeType<[???]>>> 
struct SomeType { 
    C mapping; 
}; 

SomeType<int, [???]> foo; 

sé que esto se puede hacer con el tiempo de ejecución indirecta, pero eso no es lo que estoy buscando.

+1

El contenedor de la biblioteca estándar de plantillas exigen que se ejemplariza con tipos completos; todo lo demás es un comportamiento indefinido. Tienes que vivir con eso. Sin embargo, puedes usar una solución de pimpl para evitarlo. –

+0

@KerrekSB ¿Es así? Maldición, regularmente he escrito arboles n-arios cuyos nodos fueron implementados en términos de 'std :: vector children'. –

+0

@KonradRudolph: Bueno, debe asegurarse de que en el momento de la instanciación el tipo esté completo. Eso puede ser un problema sutil. –

Respuesta

7

Su clase está incompleta en cualquier lugar antes de la final } de su definición. Por lo tanto, el miembro mapping está utilizando el tipo incompleto SomeType en los argumentos de plantilla de su tipo.

The standard does not allow this, and it is pure luck that it works with some STL containers.

a su segunda pregunta cae bajo la misma respuesta - es ilegal hacer eso en primer lugar.

+0

Hmm. Lamentablemente, no entiendo el argumento del artículo sobre por qué 'std :: map ' con tipos incompletos no puede funcionar en principio. ¿No se parece mucho a 'std :: vector >', que * puede * funcionar en principio ('std :: pair ' está incompleto)? Lo mismo ocurre con los otros contenedores. –

+0

Si esto necesita explicación, sugiero abrir una sala de chat, no es difícil, simplemente no es adecuada para la sección de comentarios ... Ahora, ¿cómo abro explícitamente una sala de chat sobre esto ... – Irfy

+1

Chatee aquí: http://chat.stackoverflow.com/rooms/9282/stl-with-incomplete-types – Irfy

4

No se puede definir una plantilla con parámetros predeterminados recursivos por razones obvias. Tampoco puede crear instancias de plantillas de contenedor de biblioteca estándar en tipos incompletos, porque el estándar lo dice (de lo contrario, es un comportamiento indefinido). El idioma PIMPL habitual puede ayudar, sin embargo:

#include <map> 
#include <memory> 
template <typename T> class SomeType 
{ 
    typedef std::map<T, SomeType<T>> map_type; 
    typedef std::unique_ptr<map_type> map_ptr; 
    map_ptr pimpl; 
public: 
    SomeType() : pimpl(new map_type) { } 
}; 
+1

La biblioteca boost :: container proporciona alternativas para la mayoría de los tipos de STL que permiten contenedores recursivos de tipos incompletos. Actualmente no proporciona un @order_map – mark

+0

@marca: ¡Gracias, eso es bueno saber! –

3

Aunque no se puede utilizar tipos incompletas con los contenedores, puede hacerlo con punteros inteligentes. Y si bien no se puede crear tipos de plantilla con parámetros de tipos no definidos, puede utilizar algunos trucos aquí:

template<typename T, template <typename U, typename V, typename... Args> class Container = std::unordered_map > 
struct SomeType { 
    Container<T, std::unique_ptr<SomeType> > mapping; 
}; 
+0

¿Es posible cambiar la primera línea de modo que el valor predeterminado para el contenedor sea std :: vector? –

+0

@NielsLohmann, técnicamente puede escribir 'template class Container = std :: vector>', pero sería inconsistente con 'std :: unordered_map' que. Debido a que el mapa es _assosiative_ conrtainer y el vector es solo una matriz. – Lol4t0

Cuestiones relacionadas