无法在 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, " "));

Live Example

{ 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 listauto 将把 { 13, 42 } 推导为 std::initiaizer_list<int> 因为列表只包含 ints.


如果将代码更改为

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>