为什么我不能构造一个带有括起来的初始化列表的队列/堆栈?(c++ 11)

时间:2022-10-11 17:35:44

Program 1:

项目1:

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

int main(){

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

    return EXIT_SUCCESS;
}

Program 2:

项目2:

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

int main(){

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

    return EXIT_SUCCESS;
}

Error message:

错误信息:

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

Question:
why can't queues be initialized like vectors?
I suppose they aren't sequence containers, but why would that matter?
I'm sure there is a good reason, but I can't find any explanations.

问:为什么不能像向量一样初始化队列?我想它们不是序列容器,但这又有什么关系呢?我肯定有一个很好的理由,但我找不到任何解释。

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

4.6.1 gcc(Ubuntu / Linaro 4.6.1-9ubuntu3)

3 个解决方案

#1


19  

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:

当您使用带有std:::vector的带支撑初始化器列表时,您使用的是这个(c++ 11中的新构造函数):

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

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

查看std::queue的定义,可用的构造函数是:

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.

构造函数获取initialization_list显然是不存在的。

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:

g++ 4.7可以毫无问题地接受这一点,并生成您期望的输出:

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.

编辑:我只是浏览了委员会的文件,建议在c++中添加initalizer_lists(例如,N1890, N1919, N2100, N2215, N2220),在我看来这只是一个简单的疏忽。早期的许多论文都是概念性的,但是N2220为工作论文提供了大量的提议语言。对于std::array(例如),它特别指出不需要更改。然后,它通过deque、vector、[unordered_][multi_](设置|映射),并显示每个变量所需的更改,但没有提到任何一个方向上的堆栈或队列。没有建议添加对std::initializer_list的支持,也没有建议(像std:::array)对它们的省略进行推理。

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).

我得出结论,这是一个简单的监管,这可能下滑原因有两个:1)适配器几乎是,但不是容器,和2)适配器类似乎并不很多,所以忘记它们可能是相当容易的(当然,ever-pervasive第三个原因:大多数活跃的委员会成员是非常劳累)。

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:

Edit2:我应该再增加一个细节:因为stack和queue都可以接受另一个容器进行初始化,所以您可以很容易地做如下事情:

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).

这有点冗长,但不太可能造成效率的损失(容器将作为rvalue引用传递,因此它的表示将被“窃取”,而不是复制)。但是有一点需要注意:如果您使用的容器类型与容器适配器下面的容器不匹配,您将获得副本而不是移动(因此可能会失去一些效率)。

#2


10  

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

#3


6  

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.

std::队列和std::堆栈实际上不是容器,它们是所谓的容器适配器,它使用一个容器(默认std::deque)。因此,您不能将其初始化为其他容器。

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.

要使容器能够使用初始化列表,它必须有一个构造函数以std:::initializer_list作为参数。容器适配器不会这样做。如果是故意的,或者是对标准委员会的监督,则取决于任何人的解释。

#1


19  

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:

当您使用带有std:::vector的带支撑初始化器列表时,您使用的是这个(c++ 11中的新构造函数):

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

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

查看std::queue的定义,可用的构造函数是:

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.

构造函数获取initialization_list显然是不存在的。

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:

g++ 4.7可以毫无问题地接受这一点,并生成您期望的输出:

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.

编辑:我只是浏览了委员会的文件,建议在c++中添加initalizer_lists(例如,N1890, N1919, N2100, N2215, N2220),在我看来这只是一个简单的疏忽。早期的许多论文都是概念性的,但是N2220为工作论文提供了大量的提议语言。对于std::array(例如),它特别指出不需要更改。然后,它通过deque、vector、[unordered_][multi_](设置|映射),并显示每个变量所需的更改,但没有提到任何一个方向上的堆栈或队列。没有建议添加对std::initializer_list的支持,也没有建议(像std:::array)对它们的省略进行推理。

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).

我得出结论,这是一个简单的监管,这可能下滑原因有两个:1)适配器几乎是,但不是容器,和2)适配器类似乎并不很多,所以忘记它们可能是相当容易的(当然,ever-pervasive第三个原因:大多数活跃的委员会成员是非常劳累)。

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:

Edit2:我应该再增加一个细节:因为stack和queue都可以接受另一个容器进行初始化,所以您可以很容易地做如下事情:

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).

这有点冗长,但不太可能造成效率的损失(容器将作为rvalue引用传递,因此它的表示将被“窃取”,而不是复制)。但是有一点需要注意:如果您使用的容器类型与容器适配器下面的容器不匹配,您将获得副本而不是移动(因此可能会失去一些效率)。

#2


10  

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

#3


6  

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.

std::队列和std::堆栈实际上不是容器,它们是所谓的容器适配器,它使用一个容器(默认std::deque)。因此,您不能将其初始化为其他容器。

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.

要使容器能够使用初始化列表,它必须有一个构造函数以std:::initializer_list作为参数。容器适配器不会这样做。如果是故意的,或者是对标准委员会的监督,则取决于任何人的解释。