43

这个问题指的是:

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

基于该问题,要强制使用cbegin()and cend(),需要执行以下操作,例如:

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

对于一个应该消除它的构造来说,这是很多样板代码。有没有更紧凑的方法来做到这一点?我提出问题的原因是,隐式共享容器可能会将我begin()用作分离自身的线索。

4

3 回答 3

36

更新: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 Container &crange() const noexcept { return *this; }
for (auto &v: container.crange())
于 2013-03-20T09:01:10.210 回答
14
const auto& const_container = container;

for (const auto& v: const_container ) {
于 2013-03-20T09:00:21.510 回答
12

基于范围的 for 循环从不使用cbegin()or cend()。(因此没有办法强迫它。)相反的谣言令人惊讶地多;有些人认为cbegin()andcend()被使用了,但从不尝试相同的代码在没有begin()and的情况下是否可以编译end()。下面是一个简单的例子。想必只有beginandend才会被打印出来,不管加多少const_casts。

#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;
}
于 2017-09-09T20:12:47.310 回答