堆栈模板参数

4

关注模板参数

我可以这样创建一个堆栈(来自标准库的适配器类模板)对象:

stack<int, vector<int>> myStack;

我知道第二个模板参数表示堆栈的底层数据结构。但是为什么以下代码行不会在编译时出现错误?

stack<int, vector<string>> myStack;

请注意,我声明了一个包含int类型元素的栈,但同时我声明了底层数据结构来保存string元素。

从功能上讲,它的作用就像是一个字符串元素的栈。


3
从cppreference复制一条注释:如果T与Container::value_type不是相同的类型,则其行为未定义。(自C++17起)。在您的情况下,Container::value_type == string,而T == int - Bill Lynch
哦,我明白了 ^_^ 非常感谢你。意思是行为不能保证。谢谢。 - Ahmad Jamal Mughal
3个回答

6
你正在进行未定义行为。不过,我会解释为什么它似乎能正常工作。
容器适配器std::stack包含几种类型符号,这些符号是将常用的类型重命名得到的。这里有一个列表
其中一个关注点就是std::stack::value_type。它基本上确定了方法std::stack::push和friends所期望的类型:
void push( const value_type& value );

我们还可以看到它的定义:

using value_type = typename TContainer::value_type

因此,所有操作中使用的类型实际上只基于第二种类型,即TContainer!在您的情况下,它是vector<string>::value_type,因此value_type将成为string的别名。在您的情况下,用于T的类型为int,但未被使用。 因此,一切似乎都能正常工作。

但是,即使这在您的特定编译器中可以工作,实际上是不允许的:

如果T与Container :: value_type不是相同的类型,则行为是未定义的。(自C++17以来)

您可以在此处找到此引用的来源。


不是楼主,但我想知道为什么它被留作UB,而不需要使用一些“static_assert”来报错。 - Dan M.
@Dan M:我不知道背后的确切原因,但这通常是标准中的做法。我猜这是为了给实现一些自由度。但由于它是未定义行为,实现可能会选择发出诊断。 - nshct

1

来自文档:

T - 存储元素的类型。如果T与Container :: value_type不是相同的类型,则行为未定义。(自C++17起)

未定义的行为意味着它可能会编译,甚至可能工作,或者可能会清除您的硬盘。

如果失败了,它将是实现相关的。


清空我的硬盘 :D 我理解了这个概念,谢谢 ^_^ - Ahmad Jamal Mughal

0

如果我要猜的话,我会想象你的实现正在丢弃int模板参数,而只是使用Container::value_type

一旦我们进入C++17,这将明确成为非法。一些编译器已经不欣赏这段代码了。

例如:

#include <stack>
#include <string>
#include <vector>

int main() {
    std::stack<int, std::vector<std::string>> s;
    s.push(3);
}

在OS X下(clang,libc ++,c++11)编译失败并返回如下错误:

blah.cc:7:7: error: no matching member function for call to 'push'
    s.push(3);
    ~~^~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/stack:194:10: note: 
      candidate function not viable: no known conversion from 'int' to 'const value_type' (aka
      'const std::__1::basic_string<char>') for 1st argument
    void push(const value_type& __v) {c.push_back(__v);}
         ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/stack:197:10: note: 
      candidate function not viable: no known conversion from 'int' to 'value_type' (aka 'std::__1::basic_string<char>') for
      1st argument
    void push(value_type&& __v) {c.push_back(_VSTD::move(__v));}
         ^
1 error generated.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接