This question refers to:
When should I use the new ranged-for and can I combine it with the new cbegin/cend?
Based on that question, to force the use of
Update: std::as_const will be in C++17, in the <utility>
header.
Prior to C++17, there's no built-in syntax for it; however, you can easily write a convenience wrapper:
template<typename T> constexpr const T &as_const(T &t) noexcept { return t; }
for (auto &v: as_const(container))
Note that this calls begin() const
rather than cbegin()
specifically; the Standard container general requirements specify that cbegin()
and begin() const
behave identically.
If your container treats non-const iteration specially, it might make sense for it itself to have a member function:
const Container &crange() const noexcept { return *this; }
for (auto &v: container.crange())
The range-based for loop never uses cbegin()
or cend()
. (Therefore there is no way to force it.) There are surprisingly many rumors to the contrary; some believe that cbegin()
and cend()
are used, but never try whether the same code would compile without begin()
and end()
. A trivial example follows. Presumably, only begin
and end
will be printed out, no matter how many const_cast
s are added.
#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 ) {