2012-04-24 10 views
7

programu 1:Dlaczego nie mogę utworzyć kolejki/stosu z listami inicjalizującymi zamkniętymi w nawiasach klamrowych? (C++ 11)

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

int main(){ 

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

    return EXIT_SUCCESS; 
} 

programu 2:

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

int main(){ 

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

    return EXIT_SUCCESS; 
} 

komunikat błędu:

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 

Pytanie: dlaczego kolejki nie mogą być inicjowane jak wektory?
Przypuszczam, że nie są to pojemniki sekwencyjne, ale dlaczego miałoby to mieć znaczenie?
Jestem pewien, że istnieje dobry powód, ale nie mogę znaleźć żadnych wyjaśnień.

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

Można sprawdzić odniesienia na pojemnikach [tutaj] (http://www.cplusplus.com/reference/stl/). Możesz również zajrzeć do boost :: assign library [here] (http://www.boost.org/doc/libs/1_42_0/libs/assign/doc/index.html). –

Odpowiedz

18

Nie sądzę, że to naprawdę ma coś wspólnego z adapterem kontenera, a nie z pojemnikami (chociaż przyznaję, że nie jestem pewien, dlaczego pominięto poprawny konstruktor).

Podczas korzystania listę initializer usztywnione z std::vector, używasz ten (nowy w C++ 11) Konstruktor:

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

Patrząc na definicję std::queue, dostępne są konstruktorzy:

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&); 

Konstruktor pobierający listę inicjalizacyjną jest wyraźnie nieobecny.

Jestem przekonany, że mimo że jest to adapter kontenera, taki konstruktor byłby banalny, gdyby był pożądany. Wystarczy na przykład:

#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 akceptuje to bez żadnych problemów, a produkuje dokładnie wyjście można się spodziewać:

1 
2 
3 
4 

Mimo, że nie zostały przetestowane z innych kompilatorów, mogę” Z jakiegoś powodu inne kompilatory nie działałyby dobrze z tym również (o ile oczywiście wprowadzą niezbędne funkcje).

Edycja: Właśnie przeglądałem papiery komisji proponujące dodanie initalizer_lists do C++ (np. N1890, N1919, N2100, N2215, N2220) i wygląda to na proste niedopatrzenie. Wiele z wcześniejszych artykułów jest bardziej konceptualnych, ale N2220 ma sporo proponowanego języka dla dokumentu roboczego. W przypadku std::array (na przykład) wyraźnie zaznaczono, że nie jest potrzebna żadna zmiana. Następnie przechodzi przez deque, vector, i pokazuje zmiany potrzebne dla każdego - ale w ogóle nie ma wzmianki o stosie lub kolejce, w żadnym kierunku. Brak propozycji dodania obsługi dla std::initializer_list ani (jak std::array) uzasadnienia ich pominięcia.

Doszłam do wniosku, że był to prosty niedopatrzeń, który prawdopodobnie prześlizgnął się z dwóch powodów: 1) adaptery są prawie, ale nie całkiem pojemnikami, i 2) klasy adapterów nie wydają się być używane w całości dużo, więc zapomnienie o nich było prawdopodobnie dość łatwe (i, oczywiście, wszechobecny trzeci powód: większość aktywnych członków komisji jest okropnie przepracowanych).

Edit2: Powinienem chyba dodać jeden szczegół: od stack i queue może zarówno przyjąć inny pojemnik do inicjalizacji, można dość łatwo zrobić coś takiego:

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

Jest to nieco rozwlekły, ale mało prawdopodobne, aby powoduje utratę wydajności (kontener zostanie przekazany jako referencja rwartości, więc jego reprezentacja zostanie "skradziona" zamiast skopiowana). Jest jednak jedno zastrzeżenie: jeśli typ używanego kontenera nie pasuje do kontenera znajdującego się pod adapterem kontenera, otrzymasz kopię, a nie ruch (i w konsekwencji, możesz stracić trochę wydajności).

+0

syn pistoletu. Właśnie skończyłem pisać identyczny kod –

+2

Zamiast implementować samemu, możesz odziedziczyć potrzebny adapter kontenera i dodać konstruktor listy inicjalizatorów. Użyj konstruktorów forwardujących C++ 11, aby nie trzeba było implementować konstruktorów klasy podstawowej. –

+2

Taka poniżej przegłosowana odpowiedź za zaproponowanie dwóch realistycznych rozwiązań plus podsumowanie odpowiednich dokumentów. –

6

std::queue i std::stack nie są faktycznie pojemniki, są tzw kontenerów adaptery który wykorzystuje pojemnik (domyślnie std::deque). Dlatego nie można go zainicjować jako innych kontenerów.

Edit

do pojemnika, aby móc korzystać z listy initializer, musi mieć konstruktor bierze się std::initializer_list jako argument. Adaptery kontenerów tego nie robią. Jeśli jest to celowe lub nadzór komisji normalizacyjnej zależy od interpretacji.

+0

W skrócie 'std :: queue',' std :: stack' i 'std :: priorityqueue' to * Adaptery kontenerów *, Kontenery zbudowane przy użyciu innych standardowych kontenerów bibliotecznych. –

+1

Mimo to mogą wywołać podstawowy kontener z listą inicjalizacji. Czy istnieje powód, dla którego tak się nie dzieje? – RedX

+0

Mogę zainicjować std :: deque. Czyż te adaptery nie są w istocie dankami o mniejszej funkcjonalności? także, co @RedX powiedział –

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

Czy to działa? W jaki sposób? – Narek

+2

To jest dobre, przypuszczam, że działa, ponieważ jeden z konstruktorów kolejki akceptuje podstawowy typ kontenera. lista inicjalizatorów jest najpierw konwertowana na tę, ponieważ kompilator może wykonać jedną niejawną konwersję, a następnie wywoływany jest konstruktor kolejki z zainicjowanym kontenerem – iggy

Powiązane problemy