为什么 ADL 不适用于未命名的 initializer_list?
Why does ADL not work with an unnamed initializer_list?
考虑以下代码。在这里,如果我们在未命名的 initializer_list
上使用 std::begin
并显式使用 std::
,它可以正常工作。如果我们省略 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
)但使用未命名的却失败?
but fail with an unnamed one?
不,{1,3,6,823,-35}
不是未命名的 std::initializer_list
。 {1,3,6,823,-35}
是一个 braced-init-list。即使它可以用于在指定的上下文中构造 std::initializer_list
但它本身不是 std::initializer_list
。那么 ADL 将不适用于 begin({1,3,6,823,-35})
.
A braced-init-list is not an expression and therefore has no type, e.g. decltype({1,2})
is ill-formed.
和
A special exception is made for type deduction using the keyword auto
, which deduces any braced-init-list as std::initializer_list
.
这就是第二种情况有效的原因; list
推导为 std::initializer_list&&
。
考虑以下代码。在这里,如果我们在未命名的 initializer_list
上使用 std::begin
并显式使用 std::
,它可以正常工作。如果我们省略 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
)但使用未命名的却失败?
but fail with an unnamed one?
不,{1,3,6,823,-35}
不是未命名的 std::initializer_list
。 {1,3,6,823,-35}
是一个 braced-init-list。即使它可以用于在指定的上下文中构造 std::initializer_list
但它本身不是 std::initializer_list
。那么 ADL 将不适用于 begin({1,3,6,823,-35})
.
A braced-init-list is not an expression and therefore has no type, e.g.
decltype({1,2})
is ill-formed.
和
A special exception is made for type deduction using the keyword
auto
, which deduces any braced-init-list asstd::initializer_list
.
这就是第二种情况有效的原因; list
推导为 std::initializer_list&&
。