为什么在C ++ 11中为std :: initializer_list重载了std :: begin()和std :: end()?

时间:2014-08-09 05:44:01

标签: c++ c++11 initializer-list

在C ++ 11中(引用N3337),std::begin()std::end()被指定为(§24.7[iterator.range] / p2-3)

template <class C> auto begin(C& c) -> decltype(c.begin());
template <class C> auto begin(const C& c) -> decltype(c.begin());
     

2返回:c.begin()

template <class C> auto end(C& c) -> decltype(c.end());
template <class C> auto end(const C& c) -> decltype(c.end());
     

3返回:c.end()

但是,

std::initializer_list为这些函数提供了自己的重载(第18.9.3节[support.initlist.range]):

template<class E> const E* begin(initializer_list<E> il) noexcept;
     

1返回:il.begin()

template<class E> const E* end(initializer_list<E> il) noexcept;
     

2返回:il.end()

除了(1)具有noexcept规范和(2)按值获取参数之外,这些重载似乎不会超出基本模板。但是,复制initializer_list没有什么特别之处(它只复制一对指针或同样轻量级的东西),因此(2)在行为上没有任何区别。此外,许多标准容器的begin()end()成员函数也是noexcept,但是没有为这些容器指定std::begin() / std::end()的重载,所以委员会似乎不太可能只针对(1)指定这些重载。那么,为什么要提供这些重载?

1 个答案:

答案 0 :(得分:7)

这在N2930中有解释,它提出了更改以添加有问题的重载。 强调我的:

  

建议更改摘要

     
      
  • 使用开头和结尾的参数依赖查找(始终包括命名空间begin中的endstd函数)来指定不使用概念的基于范围的语句提供迭代器到序列的开头和结尾。
  •   
  • 为语句指定基于范围的内容,以便数组和初始值设定项列表与<iterator>无依赖关系。
  •   
  • 重构<initializer_list>,使其不与其他标头相关,也不包含其他标头。
  •   
  • 指定要#include <initializer_list>
  • 的库标题   

似乎他们没有解释为什么他们希望<initializer_list>不依赖<iterator>,但我认为合理的猜测是前者应该是可以独立实施,而后者可能不是(表16,§17.6.1.3)