【问题标题】:Why is no compile-time error when calling an ambiguous ctor?为什么调用模棱两可的ctor时没有编译时错误?
【发布时间】:2019-08-27 05:36:32
【问题描述】:
#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&lt;std::size_t&gt;(std::size_t{8}) 来电

explicit vector(size_type count)

std::vector&lt;std::size_t&gt;{std::size_t{8}} 来电

vector(std::initializer_list&lt;T&gt; init, const Allocator&amp; alloc = Allocator()).

令我惊讶的是:

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

In another related question,一段类似的代码确实会引发歧义错误。

【问题讨论】:

  • 大括号 {} 的使用使其明确。如果可用,它将始终使用std::initializer_list 构造函数。
  • 为什么这个会触发歧义错误? stackoverflow.com/questions/41507602/…
  • 如果类型匹配,initializer_list 具有更高的优先级

标签: c++ c++11 initializer-list ambiguous overload-resolution


【解决方案1】:

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

[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构造函数。

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

【讨论】:

    猜你喜欢
    • 2013-11-04
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    相关资源
    最近更新 更多