我可以像这样创建一个堆栈(来自标准库的适配器类模板)对象,
stack<int, vector<int>> myStack;
我知道第二个模板参数意味着堆栈的底层数据结构。但是为什么以下行不会产生编译时错误?
stack<int, vector<string>> myStack;
请注意,我声明堆栈包含int
类型的元素,但同时我声明基础数据结构包含string
元素。
从功能上讲,它就好像是一堆字符串元素。
答案 0 :(得分:6)
您正在做的是未定义的行为。不过,我将解释为什么它似乎工作正常。
容器适配器std::stack<T, TContainer>
包含多个类型符号,这些符号是常用类型的别名。有一个列表here。
我们这里关注的是std::stack::value_type
。它基本上决定了方法std::stack::push
和朋友期望的类型:
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起)
您可以找到此引文的来源here。
答案 1 :(得分:1)
来自文档:
T - 存储元素的类型。如果T与Container :: value_type的类型不同,则行为未定义。 (自C ++ 17起)
未定义的行为意味着它可能会编译,甚至可能会起作用,或者它可能会擦除您的硬盘驱动器。
如果失败,如果失败,则取决于实现。
答案 2 :(得分: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.