Question

The auto type of C++11 is handy, so now one wants a const_auto type, too. For example, supposing std::list<T> a;, if

auto p = a.begin();

has the type std::list<T>::iterator, then one wishes that

const_auto p = a.begin();

had the type std::list<T>::const_iterator. Unfortunately, C++11 does not seem to have heard of const_auto. Therefore, how can one achieve the desired effect with good style, please?

(For information, a related question is asked and answered here.)

Was it helpful?

Solution

C++11 does allow you to write

const auto p = a.begin();

However, this doesn't do what you want. This makes a regular iterator to non-constant data whose value cannot be changed.

The type of the right-hand side a.begin()is determined by the type of a, and not by anything on the left-hand side. If a is non-const, then the non-const version of a.begin() will be called. So, you could cast a to a const& and then use it, or you could make a constant reference to a and use that:

const auto& b = a;
auto p = b.begin();

However, a simpler approach would be to use the newly introduced .cbegin() and .cend():

auto p = a.cbegin();

OTHER TIPS

I often find it useful to turn instances into the const version of their type, but I find using const_cast to be vulgar for this purpose (reserve that for removing const, and now searching for it finds dangerous code), and it is overly verbose (repeating the full type? Gah!)

Hence this snippet:

template<typename T>
T const& as_const( T& t ) { return t; }

which you'd then use to solve your problem as follows:

auto p = as_const(a).begin();

which I believe is pretty self documenting.

There are function templates for STL containers and C arrays in C++11. See std::begin() and std::end(). Unfortunately, there is no equivalent std::cbegin() or std::cend() for some reason.

You can use these functions to do what you want though:

template<class T, size_t N>
T const * cbegin(T(&a)[N])
{
    return &a[0];
}

template<class T, size_t N>
T const * cend(T(&a)[N])
{
    return &a[N];
}

template<class T>
typename T::const_iterator cbegin(T const & container)
{
    return container.cbegin();
}

template<class T>
typename T::const_iterator cend(T const & container)
{
    return container.cend();
}

The last two can also be declared as:

template<class T>
auto cbegin(T const & container) -> decltype(container.cbegin())
{
    return container.cbegin();
}

template<class T>
auto cend(T const & container) -> decltype(container.cend())
{
    return container.cend();
}

From there you can do this:

char x[] = "ab";

auto b = cbegin(x);
auto e = cend(x);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top