Подтвердить что ты не робот

Заставляя использовать cbegin()/cend() в диапазоне для

Этот вопрос относится к:

Когда я должен использовать новый диапазон и могу ли я объединить его с новым cbegin/cend?

На основании этого вопроса, чтобы принудительно использовать cbegin() и cend(), нужно сделать, например:

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

Это много шаблонов для конструкции, которая должна была ее устранить. Есть ли еще более компактный способ сделать это? Причина моего вопроса заключается в том, что неявный общий контейнер может использовать begin() в качестве ключа для отсоединения себя.

4b9b3361

Ответ 1

Обновление: std::as_const будет в С++ 17 в заголовке <utility>.

До С++ 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())

Ответ 2

const auto& const_container = container;

for (const auto& v: const_container ) {

Ответ 3

Цикл, основанный на диапазоне, никогда не использует cbegin() или cend(). (Поэтому нет способа заставить его.) Удивительно много слухов об обратном; некоторые считают, что используются cbegin() и cend(), но никогда не пытайтесь скомпилировать один и тот же код без begin() и end(). Ниже приводится тривиальный пример. Предположительно, будут напечатаны только begin и end, независимо от того, сколько const_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;
}