Oli*_*ock 3 c++ overloading initializer-list language-lawyer overload-resolution
为什么 C++ 选择原始类型重载匹配而不是“更好”的匹配初始值设定项列表?
#include <vector>
void foo([[maybe_unused]] int i) {}
void foo([[maybe_unused]] const std::vector<int>& v) {}
int main() {
foo(0);
foo({1,2,3});
foo({0}); // calls foo(int) and issues a warning,
// rather than what seems like the "better"
// match foo(vector).. why?
}
Run Code Online (Sandbox Code Playgroud)
<source>:10:9: warning: braces around scalar initializer [-Wbraced-scalar-init]
foo({0}); // calls foo(int) and issues a warning,
^~~
Run Code Online (Sandbox Code Playgroud)
也许是“令人惊讶”的结果,因为编译器选择了随后发出诊断的选项?
使用 Clang 14
{0}没有类型,所以我们需要尝试将其转换为重载集的参数类型。当考虑
void foo([[maybe_unused]] const std::vector<int>& v) {}
Run Code Online (Sandbox Code Playgroud)
我们需要查阅[over.ics.list]/7.2,其中指出
否则,隐式转换序列是用户定义的转换序列,其第二标准转换序列是恒等转换。
所以我们有一个用户定义的转换序列。
看着
void foo([[maybe_unused]] int i) {}
Run Code Online (Sandbox Code Playgroud)
我们发现[over.ics.list]/10.1中涵盖了转换,其中指出
如果初始值设定项列表中有一个元素本身不是初始值设定项列表,则隐式转换序列是将元素转换为参数类型所需的序列;
本例中的元素是0,它是一个整数文字,它是精确匹配标准转换
现在我们有了用户定义的转换与标准转换,并且[over.ics.rank]/2.1涵盖了这一点
标准转换序列是比用户定义的转换序列或省略号转换序列更好的转换序列,并且
现在我们知道标准转换是更好的转换,这就是int选择重载而不是std::vector<int>重载的原因。