为什么 ADL 不适用于未命名的initializer_list

Why does ADL not work with an unnamed initializer_list?

本文关键字:initializer list 未命名 ADL 不适用 适用于 为什么      更新时间:2023-10-16

请考虑以下代码。在这里,如果我们在具有显式std::的未命名initializer_list上使用std::begin,它可以正常工作。如果我们省略std::并在命名initializer_list上使用begin ,它也可以正常工作。但是,如果我们省略std::并像第一种情况一样执行其余操作,则无法编译。

#include <iostream>
#include <iterator>
void func(int len, const int* x)
{
    for(int i=0;i<len;++i)
        std::cout << x[i] << "n";
}
int main()
{
    {
        // OK
        func(5, std::begin({1,3,6,823,-35}));
    }
    {
        // OK
        auto&& list = {1,3,6,823,-35};
        func(5, begin(list));
    }
//  {
//      // Fails to compile
//      func(5, begin({1,3,6,823,-35}));
//  }
}

我收到以下编译错误(在我取消注释错误代码后(:

test.cpp: In function ‘int main()’:
test.cpp:21:11: error: ‘begin’ was not declared in this scope
   func(5, begin({1,3,6,823,-35}));
           ^~~~~
test.cpp:21:11: note: suggested alternative:
In file included from /usr/include/c++/8/string:51,
                 from /usr/include/c++/8/bits/locale_classes.h:40,
                 from /usr/include/c++/8/bits/ios_base.h:41,
                 from /usr/include/c++/8/ios:42,
                 from /usr/include/c++/8/ostream:38,
                 from /usr/include/c++/8/iostream:39,
                 from test.cpp:1:
/usr/include/c++/8/bits/range_access.h:105:37: note:   ‘std::begin’
   template<typename _Tp> const _Tp* begin(const valarray<_Tp>&);
                                     ^~~~~

为什么 ADL 适用于命名initializer_list(即 list在上面的例子中(,但失败了一个未命名的?

但是失败了一个未命名的?

不,{1,3,6,823,-35}不是一个未命名的std::initializer_list. {1,3,6,823,-35}是一个带括号的初始化列表。即使它可以用来在指定的上下文中构造std::initializer_list,但它本身并不std::initializer_list。那么 ADL 将不适用于begin({1,3,6,823,-35}).

大括号的初始化列表不是表达式,因此没有类型,例如 decltype({1,2})格式不正确。

使用关键字 auto 进行类型推导有一个特殊的例外,它将任何带大括号的 init-list 推导出为 std::initializer_list

这就是第二种情况起作用的原因; list被贬为std::initializer_list&&.