c++ - vector 构造函数的另一个违反直觉的行为

标签 c++ vector overloading language-lawyer

我希望您发现这个问题和答案具有指导性/教育性(至少对你们中的一些人来说)。
首先,让我们尝试猜测该程序的输出:

#include <vector>
#include <iostream>

using namespace std;

int main() {
  vector<char> delimiters = { ",", ";" };  
  cout << delimiters[0];
}

尝试回答 2 个问题:

  1. 该程序格式正确吗?
  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¶说:“前向迭代器 == 的域是同一底层序列上的迭代器的域。”。所以这个程序的结果是未定义的。

所以我们问题的答案是:

  1. 该程序格式不正确。
  2. 程序的输出是有限的。

关于c++ - vector 构造函数的另一个违反直觉的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66625332/

相关文章:

algorithm - 为查询索引 Haskell 数据结构

c# - 为什么 WCF 中不允许方法重载?

c++ - 是否可以将 dll 添加到资源中,并使用 LoadLibrary 从资源中加载该 dll? C++

c++ - OpenGL 使用 glNewList 和 glDrawElements

c++ - 使用 Google Test 中的 EXPECT_EQ 比较两个 boost::variant 对象

vector - Corona SDK 矢量圆圈抗锯齿 - 有效吗?

c++ - 我可以在 android studio 中使用用 xcode 编译的 c++ 静态库吗?

java vector 到arraylist

haskell - Haskell 中的重载(show 和 num)

c++ - 不同非类型模板参数的不同成员函数