无法在 cbegin 中定义 initializer_list
Can't Define an initializer_list in cbegin
所以我可以这样做:
for(const auto i : { 13, 42 }) cout << i << ' ';
但是我做不到:
copy_n(cbegin({ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
它给我错误:
error: no matching function for call to cbegin(<brace-enclosed initializer list>)
允许这个但不允许 cbegin
函数的 for
语句是什么?
编辑:
看来问题是我的 initializer_list
没有被视为 initializer_list
,因为如果我这样做它会起作用:
copy_n(cbegin(initializer_list<int>{ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
{ 13, 42 }
是大括号初始化列表。它没有类型,它只是一个列表,它取决于它的使用方式和处理方式。 std::cbegin
定义为
template< class C >
constexpr auto cbegin( const C& c ) -> decltype(std::begin(c));
并且由于大括号初始化器列表没有类型,模板类型推导失败。在基于范围的 for 循环中,我们使用不同的列表。基于 for 循环的范围扩展到
{
init-statement
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
auto && __range = range_expression ;
变为 auto && __range = { 13, 42 }
。现在 auto
遵循模板类型推导,除了因为委员会决定 auto
should work with braced initializer list,auto
将把 { 13, 42 }
推导为 std::initiaizer_list<int>
因为列表只包含 int
s.
如果将代码更改为
copy_n(begin({ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
即使 std::begin
的定义类似于 cbegin
并采用模板类型,<initializer_list>
introduces an overload 采用 std::initializer_list
并且将被调用.
初始化器列表仅存储指向原始列表的指针,并且在设计上不允许用户修改数据,即
const T* begin(); // returns a constant object
因此 begin
成员或 begin
自由函数等同于 cbegin
。这就是为什么只有 begin
存在的原因。
更新
关于 cbegin(std::initializer_list<int>...
:这是有效的,因为你明确指定了类型,cbegin(const Container&...
实际上是一个模板函数,而 begin(std::initializer_list<U>...
是一个不同的模板函数,正如我在第一个中所说的部分答案没有 cbegin(std::initializer_list<U>...
函数。
而解决的部分是你不能做"chained"模板推导,它没有意义:Container -> std::initializer_list<U> -> std::initializer_list<int>
。两种推导可能只存在一种,要么是Container -> std::initializer_list<int>
,要么是std::initializer_list<U> -> std::initializer_list<int>
所以我可以这样做:
for(const auto i : { 13, 42 }) cout << i << ' ';
但是我做不到:
copy_n(cbegin({ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
它给我错误:
error: no matching function for call to
cbegin(<brace-enclosed initializer list>)
允许这个但不允许 cbegin
函数的 for
语句是什么?
编辑:
看来问题是我的 initializer_list
没有被视为 initializer_list
,因为如果我这样做它会起作用:
copy_n(cbegin(initializer_list<int>{ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
{ 13, 42 }
是大括号初始化列表。它没有类型,它只是一个列表,它取决于它的使用方式和处理方式。 std::cbegin
定义为
template< class C >
constexpr auto cbegin( const C& c ) -> decltype(std::begin(c));
并且由于大括号初始化器列表没有类型,模板类型推导失败。在基于范围的 for 循环中,我们使用不同的列表。基于 for 循环的范围扩展到
{
init-statement
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
auto && __range = range_expression ;
变为 auto && __range = { 13, 42 }
。现在 auto
遵循模板类型推导,除了因为委员会决定 auto
should work with braced initializer list,auto
将把 { 13, 42 }
推导为 std::initiaizer_list<int>
因为列表只包含 int
s.
如果将代码更改为
copy_n(begin({ 13, 42 }), 2, ostream_iterator<int>(cout, " "));
即使 std::begin
的定义类似于 cbegin
并采用模板类型,<initializer_list>
introduces an overload 采用 std::initializer_list
并且将被调用.
初始化器列表仅存储指向原始列表的指针,并且在设计上不允许用户修改数据,即
const T* begin(); // returns a constant object
因此 begin
成员或 begin
自由函数等同于 cbegin
。这就是为什么只有 begin
存在的原因。
更新
关于 cbegin(std::initializer_list<int>...
:这是有效的,因为你明确指定了类型,cbegin(const Container&...
实际上是一个模板函数,而 begin(std::initializer_list<U>...
是一个不同的模板函数,正如我在第一个中所说的部分答案没有 cbegin(std::initializer_list<U>...
函数。
而解决的部分是你不能做"chained"模板推导,它没有意义:Container -> std::initializer_list<U> -> std::initializer_list<int>
。两种推导可能只存在一种,要么是Container -> std::initializer_list<int>
,要么是std::initializer_list<U> -> std::initializer_list<int>