在基于范围的for中强制使用cbegin()/cend()

forcing use of cbegin()/cend() in range-based for

本文关键字:cbegin cend for 于范围 范围      更新时间:2023-10-16

这个问题指的是:

我什么时候应该使用新的range -for,我可以将它与新的cbegin/cend结合使用吗?

根据这个问题,要强制使用cbegin()cend(),需要这样做,例如:

for (auto& v: const_cast<decltype(container) const>(container))

对于一个应该消除它的结构来说,这是大量的样板代码。有没有更紧凑的方法?我的问题的原因是,隐式共享容器可能会把我使用begin()作为分离自身的线索。

更新:std::as_const将在c++ 17中,在<utility>头中。

在c++ 17之前,它没有内置语法;但是,您可以轻松地编写一个方便的包装器:

template<typename T> constexpr const T &as_const(T &t) noexcept { return t; }
for (auto &v: as_const(container))

注意,这调用begin() const而不是cbegin();标准容器通用要求指定cbegin()begin() const的行为相同。

如果容器对非const迭代进行了特殊处理,则它本身有一个成员函数可能是有意义的:

const Container &crange() const noexcept { return *this; }
for (auto &v: container.crange())

基于范围的for循环从不使用cbegin()cend()。(因此没有办法强迫它。)令人惊讶的是,有许多谣言与之相反;有些人认为使用了cbegin()cend(),但从未尝试过没有begin()end()是否可以编译相同的代码。下面是一个简单的例子。假设,无论添加多少个const_cast,只会打印出beginend

#include <iostream>
class Iterable {
  struct Iterator {
    bool operator !=(const Iterator &) { return false; }
    int operator *(){ return 0; }
    Iterator& operator ++() { return *this; }
  };
public:
  Iterator cbegin() const noexcept {
    std::cout << "cbegin" << std::endl;
    return Iterator{};
  }
  Iterator cend() const noexcept {
    std::cout << "cend" << std::endl;
    return Iterator{};
  }
  Iterator begin() const noexcept {
    std::cout << "begin" << std::endl;
    return Iterator{};
  }
  Iterator end() const noexcept {
    std::cout << "end" << std::endl;
    return Iterator{};
  }
};
int main() {
  Iterable a;
  const Iterable b;
  for (auto i : a) {}
  for (auto i : b) {}
  for (const auto &i : a) {}
  for (const auto &i : b) {}
  return 0;
}
const auto& const_container = container;
for (const auto& v: const_container ) {