Reputation: 14454
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.)
Upvotes: 3
Views: 264
Reputation: 275720
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.
Upvotes: 3
Reputation: 10911
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);
Upvotes: 2
Reputation: 744
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();
Upvotes: 13