46

假设您正在编写一个接受被std::initializer_list调用list的函数,并且该函数需要随机访问list的元素。写list[i]而不是list.begin()[i]. 那么为什么不std::initializer_list提供 的定义operator[]呢?

我想不出有什么情况下operator[]退货const T&没有明确定义。效率似乎不是这里的问题,因为std::initializer_list<T>::iterator它别名为const T*,这显然是一个随机访问迭代器。

4

2 回答 2

18

根据 Bjarne Stroustrup 在 The C++ Programming Language,第 4 版的第 17.3.4.2 节(第 497 页)中:

不幸的是,initializer_list 不提供下标。

没有给出进一步的理由。

我的猜测是,这是以下原因之一:

  1. 这是一个遗漏,或者
  2. 因为 initializer_list 类是用数组实现的,并且您必须进行边界检查以提供安全访问,所以如果提供了该接口,它可能更容易被不安全地使用,或者
  3. 与 std 算法迭代范例一致,或
  4. 因为 initializer_lists 本质上是临时的,所以通过直接处理它们有更多的错误空间

2和4声音有点弱。和 3 一样。我的钱在 1 上。

于 2013-07-24T00:06:42.857 回答
7

确实有点烦人,std::initializer_list 没有方括号运算符,因为需要对特定索引进行随机直接访问是一个合理的场景。

但是,可以通过一些简单的代码添加此功能:

// the class _init_list_with_square_brackets provides [] for initializer_list
template<class T>
struct _init_list_with_square_brackets {
    const std::initializer_list<T>& list;
    _init_list_with_square_brackets(const std::initializer_list<T>& _list): list(_list) {}
    T operator[](unsigned int index) {
        return *(list.begin() + index);
    } 
};

// a function, with the short name _ (underscore) for creating 
// the _init_list_with_square_brackets out of a "regular" std::initializer_list
template<class T>
_init_list_with_square_brackets<T> _(const std::initializer_list<T>& list) {
    return _init_list_with_square_brackets<T>(list);
}

现在我们有了一个名为 _(下划线)的新全局函数,这对于全局 C++ 方法来说可能不是一个好名字,除非我们想为 C++ 创建一些“类似 undescore”的实用程序库,它将有自己的命名空间,重载_ 用于所有其他有用用途的功能。

现在可以像这样使用新的 _ 函数:

void f(std::initializer_list<int> list) {
    cout << _(list)[2]; // subscript-like syntax for std::initializer_list!
}

int main() {
    f({1,2,3}); // prints: 3
    cout << _({1,2,3})[2]; // works also, prints: 3
    return 0;
}

需要注意的是,如果您运行 std::initializer_list 的许多项,上述提供的解决方案在性能方面并不划算,因为上述建议类型的临时对象_init_list_with_square_brackets是重复创建的。当然,这再次引发了为什么标准本身没有提供这一点的疑问。

于 2015-10-09T14:56:43.777 回答