我希望您发现这个问题和答案具有指导性/教育性(至少对你们中的一些人来说)。
首先,让我们尝试猜测该程序的输出:
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<char> delimiters = { ",", ";" };
cout << delimiters[0];
}
尝试回答 2 个问题:
- 该程序格式正确吗?
- 这个程序的输出是什么?
最佳答案
好吧,正如你们中的一些人可能认为的那样(这就是我一开始的想法),这应该会导致编译错误,因此我们将字符串文字而不是字符传递给构造函数,对吗?
错了!
这里我们尝试使用两个字符串文字而不是两个字符来初始化 vector 。
initializer-list
template <class T>vector
的构造函数定义为vector(initializer_list<T>)
通过 [vector.overview]§26.3.11.1在标准中。在我们的例子中,vector(initializer_list<char>)
.
字符串文字的类型为“array of n const char
” ([lex.string]§5.13.5¶8) ,很明显初始化列表构造函数不匹配。
然而,这个问题不会导致编译器错误,因为编译器能够找到另一个匹配的构造函数!
[over.match.list]§16.3.1.7¶1规则解释得很清楚:
“当非聚合类类型 T 的对象被列表初始化时 (...),重载决策分两个阶段选择构造函数:
— 最初,候选函数是 initializer-list constructors
类 T 和参数列表由初始化列表作为单个参数组成[我们已经看到它不匹配]。
— 如果没有找到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类 T 的所有构造函数,参数列表由初始化列表的元素组成 [在我们的例子中,是两个字符串文字“,“和 ”;” ]”。
返回[vector.overview]§26.3.11.1 ,我们找到这个候选人:
template <class InputIterator> vector(InputIterator first, InputIterator last)
请注意,InputIterator 的类型与 vector 中 T 的类型没有链接。因此,即使我们初始化一个 vector ,两个参数也可以是任意类型。唯一的要求是它们符合 InputIterator 的概念,const char[] 恰好做到了这一点。
现在构造函数认为它已将两个迭代器传递给同一序列,但实际上已将迭代器传递给两个完全不同的序列“,”和“;”。 [forward.iterators]§27.2.5¶说:“前向迭代器 == 的域是同一底层序列上的迭代器的域。”。所以这个程序的结果是未定义的。
所以我们问题的答案是:
- 该程序格式不正确。
- 程序的输出是有限的。
关于c++ - vector 构造函数的另一个违反直觉的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66625332/