为什么我不能使用大括号括起初始化列表构建队列/堆栈?(C++ 11)

Tre*_*key 16 c++ queue initialization vector c++11

计划1:

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

int main(){

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

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

计划2:

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

int main(){

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

    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

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
Run Code Online (Sandbox Code Playgroud)

问题:
为什么不能像向量一样初始化队列?
我想它们不是序列容器,但为什么会这么重要?
我确信有充分的理由,但我找不到任何解释.

gcc(Ubuntu/Linaro 4.6.1-9ubuntu3)4.6.1

Jer*_*fin 25

我不认为它与容器适配器而不是容器有任何关系(虽然我承认我不确定为什么省略了正确的构造函数).

当您使用支撑的初始化列表时 std::vector,您正在使用此(C++ 11中的新增功能)构造函数:

vector(initializer_list<T>, const Allocator& = Allocator());
Run Code Online (Sandbox Code Playgroud)

查看定义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&);
Run Code Online (Sandbox Code Playgroud)

采用initialization_list的构造函数显然不存在.

我很确定,尽管是一个容器适配器,如果需要,这样的构造函数将是微不足道的.仅举例如:

#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;
}
Run Code Online (Sandbox Code Playgroud)

g ++ 4.7接受这个没有任何问题,并产生你期望的输出:

1
2
3
4
Run Code Online (Sandbox Code Playgroud)

虽然我还没有与任何其他的编译器进行测试,我看不到任何理由其它编译器将不能与这正常工作,以及(只要它们实现必要的功能,当然).

编辑:我刚刚通过委员会的文件做了一些工作,建议在C++中添加initalizer_lists(例如,N1890,N1919,N2100,N2215,N2220),它看起来像是一个简单的疏忽.许多早期的论文更具概念性,但N2220对工作文件有相当多的建议语言.对于std::array(例如),它特别指出不需要改变.然后,它通过去deque,vector,[unordered_][multi_](set|map),表示需要针对每个变化-但没有提到栈或队列的所有,在任一方向.没有提议为他们的遗漏添加支持std::initializer_list,也没有(比如std::array)推理.

我得出结论,这是一个简单的疏忽,可能有两个原因:1)适配器几乎,但不是完全容器,2)适配器类似乎没有使用很多,所以忘了关于他们可能相当容易(当然,这是一个无处不在的第三个原因:大多数活跃的委员会成员都非常过度劳累).

Edit2:我应该再添加一个细节:既然stackqueue可以接受另一个容器进行初始化,你可以很容易地做到这样的事情:

std::stack<int> data(std::vector<int>{1,2,3,4});
Run Code Online (Sandbox Code Playgroud)

这有点冗长,但不太可能导致任何效率损失(容器将作为右值引用传递,因此其表示将被"窃取"而不是复制).有一个警告是:如果你使用的容器适配器背后的容器不符合容器的类型,你会得到一个副本,而不是移动(因此,可能会失去一些效率).

  • 您可以继承所需的容器适配器,并添加initializer-list构造函数,而不是自己实现.使用C++ 11转发构造函数,因此您不必实现基类构造函数. (2认同)
  • 这样一个未经表决的答案提供了两个可行的解决方案以及相应论文的摘要. (2认同)

Jon*_*Jon 21

queue<int> q({1, 2, 3});
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的,我想这是有效的,因为队列的构造函数之一接受底层容器类型.首先将初始化列表转换为该列表,因为允许编译器执行一次隐式转换,然后使用初始化容器调用队列的构造函数 (5认同)
  • 这也适用于std :: stack({1,2,3})`,但是优先级队列需要一个比较函子作为第一个参数。如果可以默认构造函子:`std :: priority_queue &lt;int&gt;({},{1,2,3}) (2认同)

Som*_*ude 7

std::queue并且std::stack实际上不是容器,它们是所谓的容器适配器,它使用容器(默认情况下std::deque).因此,您无法将其初始化为其他容器.

编辑

对于能够使用初始化列表的容器,它必须具有带std::initializer_listas参数的构造函数.容器适配器不这样做.如果是故意或对标准委员会的监督取决于任何人的解释.

  • 简而言之`std::queue`、`std::stack` &amp; `std::priorityqueue` 是*Container Adaptors*,使用其他标准库容器构建的容器。 (2认同)
  • 尽管如此,他们仍然可以使用初始化列表调用底层容器。有没有理由不这样做? (2认同)