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

T.C*_*.C. 8 c++ initializer-list c++11

在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());
Run Code Online (Sandbox Code Playgroud)

2返回:c.begin().

template <class C> auto end(C& c) -> decltype(c.end());
template <class C> auto end(const C& c) -> decltype(c.end());
Run Code Online (Sandbox Code Playgroud)

3返回:c.end().

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

template<class E> const E* begin(initializer_list<E> il) noexcept;
Run Code Online (Sandbox Code Playgroud)

1返回:il.begin().

template<class E> const E* end(initializer_list<E> il) noexcept;
Run Code Online (Sandbox Code Playgroud)

2返回:il.end().

看起来这些重载除了基本模板之外没有做任何事情,除了(1)有noexcept规范和(2)按值取参数.但是,复制一个initializer_list没什么特别的(它只是复制一对指针或同样轻量级的东西),所以(2)没有创建行为上的差异.此外,begin()end()许多标准集装箱的成员函数也是noexcept,但没有过载std::begin()/ std::end()针对这些容器指定的,所以它似乎不大可能委员会指定这些重载只是为(1).那么,为什么要提供这些重载?

Bri*_*ian 7

这在N2930中进行了解释,N2930提出了更改以添加有问题的重载.我的重点:

建议修改摘要

  • 在不使用概念的情况下为语句指定基于范围的语句,使用begin和end的参数相关查找(总是包括命名空间中的那些beginend函数std)来为序列的开头和结尾提供迭代器.
  • 指定基于范围的语句,以便数组和初始化列表不依赖于<iterator>.
  • 重构<initializer_list>,使其不依赖于其他标头,并且不包含其他标头.
  • 指定要的库头#include <initializer_list>.

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

  • 自从该提议以来,寻找`begin` /`end`的范围已经改变了 - 它首先寻找成员函数,因此不再需要那些重载. (3认同)