2012-04-24 9 views
7

Programa 1:¿Por qué no puedo construir una cola/pila con listas de inicialización incluidas? (C++ 11)

#include <iostream> 
#include <cstdlib> 
#include <vector> 

int main(){ 

    //compiles successfully 
    std::vector<int> vec{1,2,3,4,5}; 

    return EXIT_SUCCESS; 
} 

Programa 2:

#include <iostream> 
#include <cstdlib> 
#include <queue> 

int main(){ 

    //compiler error 
    std::queue<int> que{1,2,3,4,5}; 

    return EXIT_SUCCESS; 
} 

mensaje de error:

main.cpp: In function ‘int main()’: 
main.cpp:7:31: error: no matching function for call to ‘std::queue<int>::queue(<brace-enclosed initializer list>)’ 
main.cpp:7:31: note: candidates are: 
/usr/include/c++/4.6/bits/stl_queue.h:141:7: note: std::queue<_Tp, _Sequence>::queue(_Sequence&&) [with _Tp = int, _Sequence = std::deque<int, std::allocator<int> >] 
/usr/include/c++/4.6/bits/stl_queue.h:141:7: note: candidate expects 1 argument, 5 provided 
/usr/include/c++/4.6/bits/stl_queue.h:137:7: note: std::queue<_Tp, _Sequence>::queue(const _Sequence&) [with _Tp = int, _Sequence = std::deque<int, std::allocator<int> >] 
/usr/include/c++/4.6/bits/stl_queue.h:137:7: note: candidate expects 1 argument, 5 provided 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: std::queue<int>::queue(const std::queue<int>&) 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: candidate expects 1 argument, 5 provided 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: std::queue<int>::queue(std::queue<int>&&) 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: candidate expects 1 argument, 5 provided 

Pregunta:
¿por qué no se pueden inicializar las colas como vectores?
Supongo que no son contenedores de secuencia, pero ¿por qué importaría eso?
Estoy seguro de que hay una buena razón, pero no puedo encontrar ninguna explicación.

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

Puede consultar la referencia en los contenedores [aquí] (http://www.cplusplus.com/reference/stl/). También puede consultar la biblioteca boost :: assign [aquí] (http://www.boost.org/doc/libs/1_42_0/libs/assign/doc/index.html). –

Respuesta

18

No creo que realmente tenga algo que ver con ser adaptadores de contenedores en lugar de contenedores (aunque admito que no estoy seguro de por qué se omite el constructor correcto).

Cuando se utiliza una lista de inicialización arriostrados con std::vector, que está utilizando este (nuevo en C++ 11) constructor:

vector(initializer_list<T>, const Allocator& = Allocator()); 

En cuanto a la definición de std::queue, los constructores disponibles son:

explicit queue(const Container&); 
explicit queue(Container&& = Container()); 
template <class Alloc> explicit queue(const Alloc&); 
template <class Alloc> queue(const Container&, const Alloc&); 
template <class Alloc> queue(Container&&, const Alloc&); 
template <class Alloc> queue(const queue&, const Alloc&); 
template <class Alloc> queue(queue&&, const Alloc&); 

Un constructor que toma una initialization_list brilla por su ausencia.

Estoy bastante seguro de que a pesar de ser un adaptador de contenedor, tal constructor sería trivial si así lo deseara. Sólo por ejemplo:

#include <deque> 
#include <initializer_list> 
#include <iostream> 

template <class T, class container=std::deque<T> > 
class myqueue { 
    container data; 
public: 
    explicit myqueue(std::initializer_list<T> t) : data(t) {} 
    void pop() { data.pop_front(); } 
    T front() const { return data.front(); } 
    bool empty() const { return data.empty(); } 
}; 

int main(){ 
    myqueue<int> data {1, 2, 3, 4}; 
    while (!data.empty()) { 
     std::cout << data.front() << "\n"; 
     data.pop(); 
    } 
    return 0; 
} 

g ++ 4.7 acepta esto sin ningún problema, y ​​produce exactamente la salida de lo que espera:

1 
2 
3 
4 

Aunque no he probado con otros compiladores, no puedo No veo ningún motivo por el que otros compiladores tampoco funcionen bien (siempre que implementen las funciones necesarias, por supuesto).

Editar: Acabo de revisar los documentos del comité proponiendo la adición de initalizer_lists a C++ (por ejemplo, N1890, N1919, N2100, N2215, N2220) y me parece un simple descuido. Muchos de los artículos anteriores son más conceptuales, pero N2220 tiene una buena cantidad de lenguaje propuesto para el documento de trabajo. Para std::array (para un ejemplo) específicamente señala que no se necesita ningún cambio. Luego pasa por deque, vector, [unordered_][multi_](set|map), y muestra los cambios necesarios para cada uno, pero no se menciona la pila o cola, en ninguna dirección. No hay propuesta para agregar soporte para std::initializer_list, ni (como std::array) razonamiento por su omisión.

Concluiría que fue un simple descuido, que probablemente se deslizó por dos razones: 1) los adaptadores son casi, pero no del todo contenedores, y 2) las clases de adaptadores no parecen usarse en su totalidad mucho, así que olvidarse de ellos fue probablemente bastante fácil (y, por supuesto, la tercera razón omnipresente: la mayoría de los miembros del comité activo están terriblemente sobrecargados de trabajo).

Edit2: probablemente debería agregar un detalle más: desde stack y queue puede tanto aceptar otro recipiente para la inicialización, se puede hacer muy fácilmente algo como:

std::stack<int> data(std::vector<int>{1,2,3,4}); 

Esto es algo prolijo, pero poco probable Causa pérdida de eficiencia (el contenedor se pasará como referencia de valor, por lo que su representación será "robada" en lugar de copiada). Sin embargo, hay una advertencia: si el tipo de contenedor que utiliza no coincide con el contenedor subyacente al adaptador de contenedor, obtendrá una copia en lugar de un movimiento (y, en consecuencia, puede perder algo de eficiencia).

+0

hijo de un arma. Acabo de terminar de escribir el código idéntico –

+2

En lugar de implementarlo usted mismo, puede heredar el adaptador de contenedor que necesita y agregar el constructor de lista de inicialización. Utilice los constructores de reenvío C++ 11 para que no tenga que implementar los constructores de la clase base. –

+2

Una respuesta tan poco votada para ofrecer dos soluciones viables más un resumen de los documentos correspondientes. –

6

std::queue y std::stack no son en realidad contenedores, que se llaman así adaptadores de contenedores que utiliza un recipiente (por defecto std::deque). Por lo tanto, no puede inicializarlo como otros contenedores.

Editar

Para un contenedor para ser capaz de utilizar una lista de inicialización, debe tener un constructor teniendo una std::initializer_list como argumento. Los adaptadores de contenedor no hacen eso. Si es deliberado o un descuido del comité de estándares depende de la interpretación de alguien.

+0

En pocas palabras, 'std :: queue',' std :: stack' y 'std :: priorityqueue' son * Container Adaptors *, Containers construidos mediante el uso de otros contenedores de biblioteca estándar. –

+1

Aún así, podrían llamar al contenedor subyacente con la lista de inicialización. ¿Hay alguna razón por la cual esto no se hace? – RedX

+0

Puedo inicializar std :: deque. ¿No son estos adaptadores más o menos deques con menos funcionalidad? también, lo que @RedX dijo –

8
queue<int> q({1, 2, 3}); 
+0

¿Esto funciona? ¿Cómo? – Narek

+2

este es uno bueno, supongo que funciona porque uno de los constructores de cola acepta el tipo de contenedor subyacente. la lista de inicializadores primero se convierte a eso, ya que el compilador puede hacer una conversión implícita, y luego se llama al constructor de la cola con el contenedor inicializado – iggy

Cuestiones relacionadas