My comments on this answer got me thinking about the issues of constness and sorting. I played around a bit and reduced my issues to the fact that this code:
If constness is important to you in this instance I think you probably want to work with immutable types all the way up. Conceptually you'll have a fixed size, const array of const int
s. Any time you need to change it (e.g. to add or remove elements, or to sort) you'll need to make a copy of the array with the operation performed and use that instead.
While this is very natural in a functional language it doesn't seem quite "right" in C++. getting efficient implementations of sort, for example, could be tricky - but you don't say what you're performance requirements are.
Whether you consider this route as being worth it from a performance/ custom code perspective or not I believe it is the correct approach.
After that holding the values by non-const pointer/ smart pointer is probably the best (but has its own overhead, of course).
Well, in C++0x you can...
In C++03, there is a paragraph 23.1[lib.containers.requirements]/3, which says
The type of objects stored in these components must meet the requirements of
CopyConstructible
types (20.1.3), and the additional requirements ofAssignable
types.
This is what's currently preventing you from using const int
as a type argument to std::vector
.
However, in C++0x, this paragraph is missing, instead, T
is required to be Destructible and additional requirements on T
are specified per-expression, e.g. v = u
on std::vector
is only valid if T
is MoveConstructible and MoveAssignable.
If I interpret those requirements correctly, it should be possible to instantiate std::vector<const int>
, you'll just be missing some of its functionality (which I guess is what you wanted). You can fill it by passing a pair of iterators to the constructor. I think emplace_back()
should work as well, though I failed to find explicit requirements on T
for it.
You still won't be able to sort the vector in-place though.
std::vector
of constant object will probably fail to compile due to Assignable
requirement, as constant object can not be assigned. The same is true for Move Assignment also. This is also the problem I frequently face when working with a vector based map such as boost flat_map
or Loki AssocVector
. As it has internal implementation std::vector<std::pair<const Key,Value> >
.
Thus it is almost impossible to follow const key requirement of map, which can be easily implemented for any node based map.
However it can be looked, whether std::vector<const T>
means the vector should store a const T
typed object, or it merely needs to return a non-mutable interface while accessing.
In that case, an implementation of std::vector<const T>
is possible which follows Assignable/Move Assignable requirement as it stores object of type T
rather than const T
. The standard typedefs and allocator type need to be modified little to support standard requirements.Though to support such for a vector_map
or flat_map
, one probably needs considerable change in std::pair
interface as it exposes the member variables first & second directly.
Although this doesn't meet all of your requirements (being able to sort), try a constant vector:
int values[] = {1, 3, 5, 2, 4, 6};
const std::vector<int> IDs(values, values + sizeof(values));
Although, you may want to use a std::list
. With the list, the values don't need to change, only the links to them. Sorting is accomplished by changing the order of the links.
You may have to expend some brain power and write your own. :-(
It is true that Assignable is one of the standard requirements for vector element type and const int
is not assignable. However, I would expect that in a well-thought-through implementation the compilation should fail only if the code explicitly relies on assignment. For std::vector
that would be insert
and erase
, for example.
In reality, in many implementations the compilation fails even if you are not using these methods. For example, Comeau fails to compile the plain std::vector<const int> a;
because the corresponding specialization of std::allocator
fails to compile. It reports no immediate problems with std::vector
itself.
I believe it is a valid problem. The library-provided implementation std::allocator
is supposed to fail if the type parameter is const-qualified. (I wonder if it is possible to make a custom implementation of std::allocator
to force the whole thing to compile.) (It would also be interesting to know how VS manages to compile it) Again, with Comeau std::vector<const int>
fails to compiler for the very same reasons std::allocator<const int>
fails to compile, and, according to the specification of std::allocator
it must fail to compile.
Of course, in any case any implementation has the right to fail to compile std::vector<const int>
since it is allowed to fail by the language specification.
I would have all my const objects in a standard array.
Then use a vector of pointers into the array.
A small utility class just to help you not have to de-reference the objects and hay presto.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
class XPointer
{
public:
XPointer(int const& data)
: m_data(&data)
{}
operator int const&() const
{
return *m_data;
}
private:
int const* m_data;
};
int const data[] = { 15, 17, 22, 100, 3, 4};
std::vector<XPointer> sorted(data,data+6);
int main()
{
std::sort(sorted.begin(), sorted.end());
std::copy(sorted.begin(), sorted.end(), std::ostream_iterator<int>(std::cout, ", "));
int x = sorted[1];
}