为什么调用不明确的 ctor 时没有编译时错误?

Why is no compile-time error when calling an ambiguous ctor?

本文关键字:编译时错误 ctor 调用 不明确 为什么      更新时间:2023-10-16
#include <iostream>
#include <vector>
int main()
{
auto v1 = std::vector<std::size_t>(std::size_t{8});
std::cout << v1.size() << std::endl;
auto v2 = std::vector<std::size_t>{std::size_t{8}};
std::cout << v2.size() << std::endl;
}

代码输出:

8
1

我知道这是C++中众所周知的问题,因为:

std::vector<std::size_t>(std::size_t{8})呼叫

explicit vector(size_type count)

std::vector<std::size_t>{std::size_t{8}}呼叫

vector(std::initializer_list<T> init, const Allocator& alloc = Allocator()).

令我惊讶的是:

为什么第二次调用不会因重载解析不明确而触发编译时错误?

在另一个相关问题中,一段类似的代码确实会触发歧义错误。

因为没有可能导致错误的歧义。当我们使用列表初始化时,重载解析是明确不同的。它有意分两个阶段完成。

[over.match.list]

1 当非聚合类类型 T 的对象被列表初始化时 ([dcl.init.list](,重载解析将构造函数一分为二 阶段:

  • 最初,候选函数是类 T 和参数列表的初始值设定项列表构造函数 ([dcl.init.list]( 由作为单个参数的初始值设定项列表组成。

  • 如果未找到可行的初始值设定项列表构造函数,则再次执行重载解析,其中候选函数均为 类 T 和参数列表的构造函数由 初始值设定项列表的元素。

如果初始值设定项列表没有元素,而 T 具有默认值 构造函数,则省略第一阶段。在复制列表初始化中, 如果选择显式构造函数,则初始化为 格式不正确。[ 注意:这与其他情况不同 ([over.match.ctor], [over.match.copy](,其中仅转换 考虑构造函数进行复制初始化。此限制 仅当此初始化是 过载解决。 — 尾注 ]

在第一步中,考虑std::initializer_list构造函数。我们可以到达第二步,仅当第一个重载解析失败时才考虑其他构造函数。显然,重载解决方案不会找不到合适的std::initializer_list构造函数。

您链接到的问题不是关于初始化向量的歧义。歧义在于选择函数重载。两者都是可行的,因为两者都接受不同的向量,该向量本身可以从同一个初始值设定项列表中明确初始化。