2012-04-24 3 views
7

Programma 1:Perché non è possibile creare una coda/stack con elenchi di inizializzatori inclusi tra parentesi graffe? (C++ 11)

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

int main(){ 

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

    return EXIT_SUCCESS; 
} 

Programma 2:

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

int main(){ 

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

    return EXIT_SUCCESS; 
} 

Messaggio di errore:

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 

Domanda:
perché le code non possono essere inizializzate come i vettori?
Suppongo che non siano contenitori in sequenza, ma perché dovrebbe essere così?
Sono sicuro che c'è una buona ragione, ma non riesco a trovare spiegazioni.

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

È possibile controllare il riferimento sui contenitori [qui] (http://www.cplusplus.com/reference/stl/). Puoi anche dare un'occhiata a boost :: assign library [here] (http://www.boost.org/doc/libs/1_42_0/libs/assign/doc/index.html). –

risposta

18

Non penso che abbia davvero nulla a che fare con gli adattatori di container piuttosto che con i contenitori (anche se ammetto che non sono sicuro esattamente perché viene omesso il costruttore corretto).

Quando si utilizza una lista di inizializzazione rinforzato con std::vector, si sta utilizzando questo (nuovo in C++ 11) costruttore:

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

Guardando la definizione di std::queue, i costruttori disponibili sono:

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 costruttore che prende una lista di inizializzazione è assente.

Sono abbastanza sicuro che nonostante sia un adattatore per container, tale costruttore sarebbe banale se lo si desiderava. Basta per esempio:

#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 accetta questo senza alcun problema, e produce esattamente l'output che ci si aspetterebbe:

1 
2 
3 
4 

Anche se non ho ancora testato con altri compilatori, posso' Non vedo alcun motivo per cui altri compilatori non funzionerebbero bene con questo (a condizione che implementino le funzionalità necessarie, ovviamente).

Edit: Ho appena fatto un po 'di ricerca nei documenti del comitato proponendo l'aggiunta di initalizer_lists a C++ (ad esempio, N1890, N1919, N2100, N2215, N2220) e mi sembra una semplice svista. Molti dei primi articoli sono più concettuali, ma l'N2220 ha una buona dose di linguaggio proposto per il documento di lavoro. Per std::array (per un esempio) specifica in modo specifico che non è necessaria alcuna modifica. Passa quindi a deque, vector, [unordered_][multi_](set|map) e mostra le modifiche necessarie per ciascuna, ma non viene fatto alcun accenno allo stack o alla coda, in nessuna direzione. Nessuna proposta di aggiungere il supporto per std::initializer_list, né il ragionamento (come std::array) per la loro omissione.

Direi che si trattava di una semplice svista, che probabilmente è sfuggita per due motivi: 1) gli adattatori sono quasi, ma non abbastanza contenitori, e 2) le classi di adattatori non sembrano essere usate per intero molto, quindi dimenticarsi di loro era probabilmente abbastanza facile (e, naturalmente, la pervasiva terza ragione: la maggior parte dei membri attivi del comitato sono orribilmente oberati di lavoro).

Edit2: Probabilmente dovrei aggiungere più un dettaglio: dal stack e queue possono entrambi accettare un altro contenitore per l'inizializzazione, si può abbastanza facilmente fare qualcosa di simile:

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

è abbastanza prolisso, ma improbabile causa una perdita di efficienza (il contenitore verrà passato come riferimento di valore, quindi la sua rappresentazione sarà "rubata" anziché copiata). Tuttavia, vi è un avvertimento: se il tipo di contenitore che si utilizza non corrisponde al contenitore sottostante l'adattatore del contenitore, si otterrà una copia anziché uno spostamento (e, di conseguenza, si potrebbe perdere un po 'di efficienza).

+0

figlio di una pistola. Ho appena finito di scrivere il codice identico –

+2

Invece di implementare tutto da solo, potresti ereditare l'adattatore del contenitore che ti serve e aggiungere il costruttore dell'elenco inizializzatore. Utilizzare i costruttori di inoltro C++ 11 in modo da non dover implementare i costruttori della classe base. –

+2

Tale risposta sotto votazione per l'offerta di due soluzioni praticabili più un riassunto dei documenti corrispondenti. –

6

std::queue e std::stack non sono in realtà contenitori, sono così chiamati adattatori contenitore che utilizza un contenitore (per default std::deque). Pertanto non è possibile inizializzarlo come altri contenitori.

Modifica

Per un contenitore per essere in grado di utilizzare una lista di inizializzazione, si deve avere un costruttore di prendere un std::initializer_list come argomento. Gli adattatori contenitore non lo fanno. Se è intenzionale o una supervisione del comitato degli standard spetta all'interpretazione di qualcuno.

+0

In breve 'std :: queue',' std :: stack' e 'std :: priorityqueue' sono * Container Adapters *, Container creati utilizzando altri contenitori di libreria standard. –

+1

Ancora, potevano chiamare il contenitore sottostante con l'elenco di inizializzazione. C'è una ragione per cui questo non è fatto? – RedX

+0

Posso inizializzare std :: deque. Questi adattatori non sono forse più deques con meno funzionalità? inoltre, cosa ha detto @RedX –

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

Funziona? Come? – Narek

+2

questo è buono, suppongo che funzioni perché uno dei costruttori della coda accetta il tipo di contenitore sottostante. l'elenco di inizializzazione viene prima convertito in quello, poiché al compilatore è consentito eseguire una conversione implicita, quindi viene chiamato il costruttore della coda con il contenitore inizializzato – iggy