【问题标题】:Why std::queue allows redundant type specification?为什么 std::queue 允许冗余类型规范?
【发布时间】:2011-04-18 10:10:23
【问题描述】:

STL库类std::queue的前向声明如下:

namespace std {
    template<typename T, class container = deque<T>> class queue
}

这意味着我们可以声明一个具有不同类型规范的队列类型对象,如下所示:

std::queue<float, std::deque<std::string>> string_queue;

为什么会这样?像这样声明队列不是更安全吗:

template<class implementation>
class queue_base
{
private:
    implementation m_impl;
    /* ----------------------------------------------------------- */

public:
    typedef implementation                      container_type;
    typedef typename implementation::size_type  size_type;
    typedef queue_base<implementation>          this_type;
    typedef typename implementation::value_type value_type;
    /* ----------------------------------------------------------- */

    queue_base         ();
    queue_base         (queue_base const& other);
    explicit queue_base(container_type const& other);
    /* ----------------------------------------------------------- */

    value_type&       back ();
    value_type const& back () const;
    bool              empty() const;
    value_type&       front();
    value_type const& front() const;
    void              pop  ();
    void              push (value_type const& value);
    size_type         size () const;
    /* ----------------------------------------------------------- */
}; /* template<class> class queue_base */
/* --------------------------------------------------------------- */

我见过的大多数 std::queue 实现都以与您在上面的代码中看到的相同方式实现“value_type”和“size_type”。所以,模板参数 'T' 只用于模板参数 'container' (std::deque) 的默认参数。

我的意思是,我不认为忽略上面声明示例中的浮点规范是“好的”;不管它是否有效。

【问题讨论】:

标签: c++ templates stl containers


【解决方案1】:

这样声明队列不是更安全吗:

更多类型安全是的,但不那么方便。 queue 的普通用户并不关心底层容器,这实际上只是一个实现细节。他们只关心元素类型。这也是为了与其他容器类保持一致。

如果queue 类可以通过为容器指定一个类模板来使用会更好,如下所示:

std::queue<int, std::list> myqueue;

但不幸的是,在 C++ 中没有很好的、可移植的方法。

【讨论】:

  • 哼,我认为这是一个弱点。当我使用 std::list 而不是 std::deque 作为 std::queue 的容器时,我还需要完全输入 std::queue>.
  • @Sascha 但是你,通常使用std::list。队列的正常用例是使用默认值,即std::queue&lt;int&gt;。这并不是一个真正的弱点,针对常见情况进行优化是一个很好的设计原则。
  • 是的,我知道你的意思,但在我看来,你不应该更喜欢优化(任何形式的)而不是完整性。
  • @Sascha:嗯?失去了什么完整性?
  • @Konrad:FWIW,你可以在 C++0x 中。我在其他地方做了它作为答案,我会看看我是否能找到它。编辑:Here.
【解决方案2】:

从逻辑上讲,人们可能会期待这样的事情:

template<typename T, template<typenameU> class C = std::deque>
class queue
{
protected:
    C<T> c;
public:
    //  ...
};

问题是std::deque 不会匹配模板 论据,因为它实际上是:

template<typename T, typename Allocator = allocator<T> >
class deque ...

额外的模板参数阻止它工作。而如果 额外的参数被添加到的第二个参数 queue,那么大部分用户定义的容器都无法使用, 因为他们不会有第二个论点。目前的 解决方案回避了这个问题(同时仍然允许客户 实例化std::queue&lt;float&gt; 的代码,例如,没有 担心底层容器类型)。

最后,为什么不呢?您的 std::queue<float, std::deque<std::string> > 示例可能无法编译,但什么是 std::queue&lt;bool, std::vector&lt;char&gt; &gt; 之类的错误 (避免有问题的std::vector&lt;bool&gt;)?只要 两种方式都有隐式转换,这取决于客户 以确保它做他想做的事。 (当然,在实践中, 这几乎从来不是问题,因为客户端代码很少见 指定容器。)

【讨论】:

  • 就像我上面说的:在大多数实现中,第一个模板参数被忽略。因此,'bool' 在您的示例中没有任何意义。
  • 所以我明白了。事实上,这是标准要求的。不过,这对我来说似乎很奇怪;我的预期正好相反。 (或者某种静态断言这两种类型是相同的。)
【解决方案3】:

如果您只关心防止“愚蠢”的情况,简单的完整性检查就足够了:

template <typename T, typename Container>
class queue
{
  static_assert(std::is_same<T, typename Container::value_type>::value,
    "queue require T and Container::value_type to be identical");
};

或 C++03 中的类似设施。

【讨论】:

    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2018-10-29
    相关资源
    最近更新 更多