Заставляя использовать cbegin()/cend() в диапазоне для
Этот вопрос относится к:
Когда я должен использовать новый диапазон и могу ли я объединить его с новым cbegin/cend?
На основании этого вопроса, чтобы принудительно использовать cbegin()
и cend()
, нужно сделать, например:
for (auto& v: const_cast<decltype(container) const>(container))
Это много шаблонов для конструкции, которая должна была ее устранить. Есть ли еще более компактный способ сделать это? Причина моего вопроса заключается в том, что неявный общий контейнер может использовать begin()
в качестве ключа для отсоединения себя.
Ответы
Ответ 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;
}