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

时间:2013-03-20 08:48:23

标签: c++

这个问题涉及:

When should I use the new ranged-for and can I combine it with the new cbegin/cend?

基于该问题,强制使用cbegin()cend(),需要做的事情,例如:

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

这是一个应该消除它的构造的很多样板代码。有更紧凑的方法吗?我的问题的原因是,隐式共享容器可能会使用begin()作为分离自己的线索。

3 个答案:

答案 0 :(得分:27)

更新:std::as_const将位于<utility>标题中的C ++ 17中。

在C ++ 17 之前,它没有内置语法;但是,您可以轻松编写便利包装器:

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

请注意,这会特别调用begin() const而不是cbegin(); Standard container general requirements指定cbegin()begin() const的行为相同。

如果你的容器特别处理非常量迭代,那么它本身就有一个成员函数是有意义的:

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

答案 1 :(得分:11)

const auto& const_container = container;

for (const auto& v: const_container ) {

答案 2 :(得分:3)

基于范围的for循环从不使用cbegin()cend()。 (因此没有办法强迫它。)令人惊讶的是有许多相反的谣言;有些人认为使用cbegin()cend(),但从不尝试在没有begin()end()的情况下编译相同的代码。一个简单的例子如下。据推测,无论添加了多少begin,都只会打印endconst_cast

#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;
}