Why can't I construct a queue/stack with brace-enclosed initializer lists? (C++11)

前端 未结 3 2042
死守一世寂寞
死守一世寂寞 2021-01-31 18:52

Program 1:

#include 
#include 
#include 

int main(){

    //compiles successfully 
    std::vect         


        
相关标签:
3条回答
  • 2021-01-31 19:03

    I don't think it really has anything to do with being container adapters rather than containers (though I'll admit I'm uncertain exactly why the correct constructor is omitted).

    When you use a braced initializer list with std::vector, you're using this (new in C++11) constructor:

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

    Looking at the definition of std::queue, the available constructors are:

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

    A constructor taking an initialization_list is conspicuously absent.

    I'm quite certain that despite being a container adapter, such a constructor would be trivial if it was desired. Just for example:

    #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 accepts this without any problems, and produces exactly the output you'd expect:

    1
    2
    3
    4
    

    Although I haven't tested with any other compilers, I can't see any reason other compilers wouldn't work fine with this as well (provided they implement the necessary features, of course).

    Edit: I just did some looking through the committee papers proposing the addition of initalizer_lists to C++ (e.g., N1890, N1919, N2100, N2215, N2220) and it looks to me like a simple oversight. Many of the earlier papers are more conceptual, but N2220 has a fair amount of proposed language for the working paper. For std::array (for one example) it specifically points out that no change is needed. It then goes through deque, vector, [unordered_][multi_](set|map), and shows changes needed for each -- but no mention is made of stack or queue at all, in either direction. No proposal to add support for std::initializer_list, nor (like std::array) reasoning for their omission.

    I'd conclude that it was a simple oversight, that probably slipped through for two reasons: 1) the adapters are almost, but not quite containers, and 2) the adapter classes don't seem to be used a whole lot, so forgetting about them was probably fairly easy (and, of course, the ever-pervasive third reason: most of the active committee members are horribly overworked).

    Edit2: I should probably add one more detail: since stack and queue can both accept another container for the initialization, you can pretty easily do something like:

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

    This is somewhat verbose, but unlikely to cause any loss of efficiency (the container will be passed as an rvalue reference, so its representation will be "stolen" instead of copied). There is one caveat though: if the type of container you use doesn't match the container underlying the container adapter, you'll get a copy rather than a move (and consequently, may lose some efficiency).

    0 讨论(0)
  • 2021-01-31 19:15

    std::queue and std::stack are not actually containers, they are so called container adaptors which uses a container (by default std::deque). Therefore you can not initialize it as other containers.

    Edit

    For a container to be able to use an initializer list, it must have a constructor taking an std::initializer_list as argument. The container adaptors don't do that. If it's deliberate or an oversight of the standards committee is up to anyones interpretation.

    0 讨论(0)
  • 2021-01-31 19:18
    queue<int> q({1, 2, 3});
    
    0 讨论(0)
提交回复
热议问题