A const int * and an int *const are very different. Similarly with const std::auto_ptr<int> vs. std::auto_ptr<const int>. However, there appears to be no such distinction with const std::vector<int> vs. std::vector<const int> (actually I'm not sure the second is even allowed). Why is this?
Sometimes I have a function which I want to pass a reference to a vector. The function shouldn't modify the vector itself (eg. no push_back()), but it wants to modify each of the contained values (say, increment them). Similarly, I might want a function to only change the vector structure but not modify any of its existing contents (though this would be odd). This kind of thing is possible with std::auto_ptr (for example), but because std::vector::front() (for example) is defined as
const T &front() const;
T &front();
rather than just
T &front() const;
There's no way to express this.
Examples of what I want to do:
//create a (non-modifiable) auto_ptr containing a (modifiable) int
const std::auto_ptr<int> a(new int(3));
//this works and makes sense - changing the value pointed to, not the pointer itself
*a = 4;
//this is an error, as it should be
a.reset();
//create a (non-modifiable) vector containing a (modifiable) int
const std::vector<int> v(1, 3);
//this makes sense to me but doesn't work - trying to change the value in the vector, not the vector itself
v.front() = 4;
//this is an error, as it should be
v.clear();
It's a design decision.
If you have a const container, it usually stands to reason that you don't want anybody to modify the elements that it contains, which are an intrinsic part of it. That the container completely "owns" these elements "solidifies the bond", if you will.
This is in contrast to the historic, more lower-level "container" implementations (i.e. raw arrays) which are more hands-off. As you quite rightly say, there is a big difference between int const* and int * const. But standard containers simply choose to pass the constness on.
The difference is that pointers to int do not own the ints that they point to, whereas a vector<int> does own the contained ints. A vector<int> can be conceptualised as a struct with int members, where the number of members just happens to be variable.
If you want to create a function that can modify the values contained in the vector but not the vector itself then you should design the function to accept iterator arguments.
Example:
void setAllToOne(std::vector<int>::iterator begin, std::vector<int>::iterator end)
{
std::for_each(begin, end, [](int& elem) { elem = 1; });
}
If you can afford to put the desired functionality in a header, then it can be made generic as:
template<typename OutputIterator>
void setAllToOne(OutputIterator begin, OutputIterator end)
{
typedef typename iterator_traits<OutputIterator>::reference ref;
std::for_each(begin, end, [](ref elem) { elem = 1; });
}
One big problem syntactically with what you suggest is this: a std::vector<const T> is not the same type as a std::vector<T>. Therefore, you could not pass a vector<T> to a function that expects a vector<const T> without some kind of conversion. Not a simple cast, but the creation of a new vector<const T>. And that new one could not simply share data with the old; it would have to either copy or move the data from the old one to the new one.
You can get away with this with std::shared_ptr, but that's because those are shared pointers. You can have two objects that reference the same pointer, so the conversion from a std::shared_ptr<T> to shared_ptr<const T> doesn't hurt (beyond bumping the reference count). There is no such thing as a shared_vector.
std::unique_ptr works too because they can only be moved from, not copied. Therefore, only one of them will ever have the pointer.
So what you're asking for is simply not possible.
You are correct, it is not possible to have a vector of const int primarily because the elements will not assignable (requirements for the type of the element contained in the vector).
If you want a function that only modifies the elements of a vector but not add elements to the vector itself, this is primarily what STL does for you -- have functions that are agnostic about which container a sequence of elements is contained in. The function simply takes a pair of iterators and does its thing for that sequence, completely oblivious to the fact that they are contained in a vector.
Look up "insert iterators" for getting to know about how to insert something into a container without needing to know what the elements are. E.g., back_inserter takes a container and all that it cares for is to know that the container has a member function called "push_back".
Related
I have a vector of Foo
vector<Foo> inputs
Foo is a struct with some score inside
struct Foo {
...
float score
bool winner
}
Now I want to sort inputs by score and only assign winner to the top 3. But I don't want to change the original inputs vector. So I guess I need to create a vector of reference then sort that? Is it legal to create a vector of reference? Is there an elegant way to do so?
Here two different way of creating a vector<Foo*>:
vector<Foo*> foor;
for (auto& x:inputs)
foor.push_back(&x);
vector<Foo*> foob(inputs.size(),nullptr);
transform(inputs.begin(), inputs.end(), foob.begin(), [](auto&x) {return &x;});
You can then use standard algorithms to sort your vectors of pointers without changing the original vector (if this is a requirement):
// decreasing order according to score
sort(foob.begin(), foob.end(), [](Foo*a, Foo*b)->bool {return a->score>b->score;});
You may finally change the top n elements, either using for_each_n() algorithm (if C++17) or simply with an ordinary loop.
Online demo
The only example code given was for pointers, and the IMO far more fitting std::reference_wrapper was only mentioned, with no indication of how it might be used in a situation like this. I want to fix that!
Non-owning pointers have at least 3 drawbacks:
the visual, from having to pepper &, *, and -> in code using them;
the practical: if all you want is a reference to one object, now you have a thing that can be subtracted from other pointers (which may not be related), be inc/decremented (if not const), do stuff in overload resolution or conversion, etc. – none of which you want. I'm sure everyone is laughing at this and saying 'I'd never make such silly mistakes', but you know in your gut that, on a long enough timeline, it will happen.
and the lack of self-documentation, as they have no innate semantics of ownership or lack thereof.
I typically prefer std::reference_wrapper, which
clearly self-documents its purely observational semantics,
can only yield a reference to an object, thus not having any pointer-like pitfalls, and
sidesteps many syntactical problems by implicitly converting to the real referred type, thus minimising operator noise where you can invoke conversion (pass to a function, initialise a reference, range-for, etc.)... albeit interfering with the modern preference for auto – at least until we get the proposed operator. or operator auto – and requiring the more verbose .get() in other cases or if you just want to avoid such inconsistencies. Still, I argue that these wrinkles are neither worse than those of pointers, nor likely to be permanent given various active proposals to prettify use of wrapper/proxy types.
I'd recommend that or another vocabulary class, especially for publicly exposed data. There are experimental proposal(s) for observer_ptrs and whatnot, but again, if you don't really want pointer-like behaviour, then you should be using a wrapper that models a reference... and we already have one of those.
So... the code in the accepted answer can be rewritten like so (now with #includes and my preferences for formatting):
#include <algorithm>
#include <functional>
#include <vector>
// ...
void
modify_top_n(std::vector<Foo>& v, int const n)
{
std::vector< std::reference_wrapper<Foo> > tmp{ v.begin(), v.end() };
std::nth_element( tmp.begin(), tmp.begin() + n, tmp.end(),
[](Foo const& f1, Foo const& f2){ return f1.score > f2.score; } );
std::for_each( tmp.begin(), tmp.begin() + n,
[](Foo& f){ f.winner = true; } );
}
This makes use of the range constructor to construct a range of reference_wrappers from the range of real Foos, and the implicit conversion to Foo& in the lambda argument lists to avoid having to do reference_wrapper.get() (and then we have the far less messy direct member access by . instead of ->).
Of course, this can be generalised: the main candidate for factoring out to a reusable helper function is the construction of a vector< reference_wrapper<Foo> > for arbitrary Foo, given only a pair of iterators-to-Foo. But we always have to leave something as an exercise to the reader. :P
If you really don't want to modify the original vector, then you'll have to sort a vector of pointers or indices into the original vector instead. To answer part of your question, no there's no way to make a vector of references and you shouldn't do so.
To find the top three (or n) elements, you don't even have to sort the whole vector. The STL's got you covered with std::nth_element (or std::partial_sort if you care about the order of the top elements), you would do something like this:
void modify_top_n(std::vector<Foo> &v, int n) {
std::vector<Foo*> tmp(v.size());
std::transform(v.begin(), v.end(), tmp.begin(), [](Foo &f) { return &f; });
std::nth_element(tmp.begin(), tmp.begin() + n, tmp.end(),
[](const Foo* f1, const Foo *f2) { return f1->score > f2->score; });
std::for_each(tmp.begin(), tmp.begin() + n, [](Foo *f) {
f->winner = true;
});
}
Assuming the vector has at least n entries. I used for_each just because it's easier when you have an iterator range, you can use a for loop as well (or for_each_n as Christophe mentioned, if you have C++17).
Answering the question on it's face value:
Vectors of references (as well as built-in arrays of them) are not legal in C++. Here is normative standard wording for arrays:
There shall be no references to references, no arrays of references,
and no pointers to references.
And for vectors it is forbidden by the fact that vector elements must be assignable (while references are not).
To have an array or vector of indirect objects, one can either use a non-owning pointer (std::vector<int*>), or, if a non-pointer access syntax is desired, a wrapper - std::reference_wrapper.
So I guess I need to create a vector of reference then sort that? Is it legal to create a vector of reference?
No, it is not possible to have a vector of references. There is std::reference_wrapper for such purpose, or you can use a bare pointer.
Besides the two ways shown by Christophe, one more way is a transform iterator adaptor, which can be used to sort the top 3 pointers / reference wrappers into an array using std::partial_sort_copy.
A transform iterator simply adapts an output iterator by calling a function to transform input upon assignment. There are no iterator adaptors in the standard library though, so you need to implement one yourself, or use a library.
http://www.cplusplus.com/reference/vector/vector/push_back/ (C++11 Version)
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?;
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
http://www.cplusplus.com/reference/vector/vector/pop_back/
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
If you are a beginner, just read over the additional qualifiers like const, & and &&. The methods in the STL are implemented in a way, that they behave consistent over all overloads:
I will give you a small example here:
std::vector<int> myvector;
myvector.push_back(5);
int five = 5;
myvector.push_back(five);
Now the more in depth part of the answer:
First (const value_type& val). The & character signals, that we take the argument by reference, that means we don't copy the argument, but get a fancy pointer, that will behave like the object itself.
You may not want, that your variable is changed, if you push it back to a vector. To get a promise, by the programmer of the STL, that he will not change your variable while pushing it back to the vector, he can add the const before the type.
The reason it is implemented that way, is that it may prevent an unneeded copy. (First copy the argument onto the stack to call push_back and the second time copy it at the position in the vector. The first copy is unnecessary and saved by the const reference.)
This is all nice and simple, but there are cases, where the compiler is not allowed to take a reference of a value and pass it to a function. In case of temporary values, there is no reference to take, because there is no variable in memory. Take the following line for example.
myvector.push_back(5);
Since the 5 has no address, it can't be passed as a reference. The compiler can not use the first overload of the function. But the programmer also does not want to waste the time for the copy onto the stack. That is why C++11 added new semantic. A so called rvalue for such temporary objects. If you want to write a function to take such an rvalue, you can do so by using type&& rvalue_variable. The value in this case the 5 is moved onto the stack by using the move constructor of the type. For trivial types like int, this will be the same as the copy constructor. For complex types like std::vector there are shortcuts one can take if one is allowed to rip the temporary object apart. In case of the vector, it does not need to copy all the data in the vector to a new location, but can use the pointer of the old vector in the new object.
Now we can look at the example again:
std::vector<int> myvector;
myvector.push_back(5); // push_back(const int&) can't be applied. The compiler chooses push_back(int&&) for us
int five = 5;
myvector.push_back(five); // push_back(const int&) can be applied and is used by the compiler
// The resulting vector after this has the two values [5, 5]
// and we see, that we don't need to care about it.
This should show you how you can use both of them.
push_back():
std::vector<int> vec = { 0, 1, 2 };
vec.push_back(3);
pop_back():
vec.pop_back();
vec.pop_back();
If you need more clarification:
push_back(const T& val) adds its parameter to the end of the vector, effectively increasing the size by 1 iff the vector capacity will be exceeded by its size.
pop_back() doesn't take any parameters and removes the last element of the vector, effectively reducing the size by 1.
Update:
I'm trying to tackle your questions one by one, if there is anything unclear, let me know.
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?;
Prior to C++11, rvalue-references didn't exist. That's why push_back was implemented as vector.push_back(const value_type& val). If you have a compiler that supports C++11 or later, std::vector.push_back() will be overloaded for const lvalue references and rvalue references.
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
You as a programmer do NOT choose how you pass arguments to push_back(), the compiler does it for you automagically, in most cases.
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
value_type is equal to the type of vector that you declared. If a vector is declared with std::string, then it can only hold std::string.
std::vector<std::string> vec;
vec.push_back("str"); // Ok. "str" is allowed.
vec.push_back(12); // Compile-time error. 12 is not allowed.
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?
void push_back(const value_type&) takes an argument, that is then copied into the vector. This means that a new element is initialized as a copy of the passed argument, as defined by an appropriate allocator.
void push_back(value_type&&) takes an argument, that is then moved into the container (this type of expressions are called rvalue expressions).
The usage of either of two depends on the results you want to achieve.
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
In most cases you shouldn't think about which version to use, as compiler will take care of this for you. Second version will be called for any rvalue argument and the first one for the rest. In a rare case when you want to ensure the second overload is called you can use std::move to explicitly convert the argument expression into xvalue (which is a kind of rvalues).
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
The sentence in question is:
Member type value_type is the type of the elements in the container, defined in vector as an alias of its first template parameter (T).
This means that value_type is the same type as the type of vector's elements. E.g., if you have vector<int> then value_type is the same as int and for vector<string> the value_type is string.
Because vector is not an ordinary type, but a template, you must specify a type parameters (which goes into angle brackets <> after vector) when defining a variable. Inside the vector template specification this type parameter T is then aliased with value_type:
typedef T value_type;
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
The main thing you need to remember is that vector behaves like a simple array, but with dynamicly changeable size and some additional information, like its length. push_back is simply a function that adds a new element at the end of this pseudo-array. There is, of course, a lot of subtle details, but they are inconsequential in most of the cases.
The basic usage is like this:
vector<int> v; // v is empty
v.push_back(1); // v now contains one element
vector<float> v2 { 1.0, 2.0 }; // v2 is now a vector with two elements
float f = v2.pop_back(); // v2 now has one element, and f is now equals 2.0
The best way to understand how it works is to try using it yourself.
For example, the following is possible:
std::set<int> s;
std::set<int>::iterator it = s.begin();
I wonder if the opposite is possible, say,
std::set<int>* pSet = it->**getContainer**(); // something like this...
No, there is no portable way to do this.
An iterator may not even have a reference to the container. For example, an implementation could use T* as the iterator type for both std::array<T, N> and std::vector<T>, since both store their elements as arrays.
In addition, iterators are far more general than containers, and not all iterators point into containers (for example, there are input and output iterators that read to and write from streams).
No. You must remember the container that an iterator came from, at the time that you find the iterator.
A possible reason for this restriction is that pointers were meant to be valid iterators and there's no way to ask a pointer to figure out where it came from (e.g. if you point 4 elements into an array, how from that pointer alone can you tell where the beginning of the array is?).
It is possible with at least one of the std iterators and some trickery.
The std::back_insert_iterator needs a pointer to the container to call its push_back method. Moreover this pointer is protected only.
#include <iterator>
template <typename Container>
struct get_a_pointer_iterator : std::back_insert_iterator<Container> {
typedef std::back_insert_iterator<Container> base;
get_a_pointer_iterator(Container& c) : base(c) {}
Container* getPointer(){ return base::container;}
};
#include <iostream>
int main() {
std::vector<int> x{1};
auto p = get_a_pointer_iterator<std::vector<int>>(x);
std::cout << (*p.getPointer()).at(0);
}
This is of course of no pratical use, but merely an example of an std iterator that indeed carries a pointer to its container, though a quite special one (eg. incrementing a std::back_insert_iterator is a noop). The whole point of using iterators is not to know where the elements are coming from. On the other hand, if you ever wanted an iterator that lets you get a pointer to the container, you could write one.
I'm parsing a file and creating a vector of a vector of Foo objects.
vector< vector<Foo*> > mFooVectors;
I have to allow access with the following getFoos function.
const vector<const Foo*>& getFoos(int index);
So I created a const declaration of my vector:
const vector< const vector<const Foo*> > mConstFooVectors;
Now how do I do mConstFooVectors = mFooVectors so I can return a reference to mConstFooVectors?
You cannot add const at any given level that easy. Different instantiations of a template are different unrelated types, a vector<T> is unrelated to a vector<const T>, and there is no way of casting from one to the other.
You can, on the other hand, create a different vector and just copy the contents, but that might be expensive, as you would have to copy all the different contained vectors.
By the way, if you return a const reference to the outer vector, the const reference will behave as: const std::vector< const std::vector< Foo * const > >&, note that because of the value semantics associated to types in C++, const-ness propagates in. The problem is that the value stored in the inner vector is a pointer, and making that pointer constant does not make the pointed-to object constant. Similarly, the behavior of your getFoos(int) will be equivalent to const std::vector< Foo * const >&. Note, that is behavior not actual types.
I don't know what you are trying to do, but I'd have a look at boost::ptr_vector
Specially, your vector member can potentially leak if you don't handle it correctly... (RAII)
vector's copy constructor should be able to handle it, but you'll have to do it in the initializer list of your class's constructor since it's a const member.
Edit: That was wrong... Vector's copy constructor can't handle it. See David Rodriguez' post for an explanation (vector and vector are unrelated types).
You are mixing a
vector<const Foo *>
with
vector<Foo *>
You have to decide which one you want - there is no way to convert from one to another (without making a copy).
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:
#include <vector>
int main() {
std::vector <const int> v;
}
will not compile - you can't create a vector of const ints. Obviously, I should have known this (and intellectually I did), but I've never needed to create such a thing before. However, it seems like a useful construct to me, and I wonder if there is any way round this problem - I want to add things to a vector (or whatever), but they should not be changed once added.
There's probably some embarrassingly simple solution to this, but it's something I'd never considered before.
I probably should not have mentioned sorting (I may ask another question about that, see this for the difficulties of asking questions). My real base use case is something like this:
vector <const int> v; // ok (i.e. I want it to be OK)
v.push_back( 42 ); // ok
int n = v[0]; // ok
v[0] = 1; // not allowed
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 of Assignable 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.
Types that you put in a standard container have to be copyable and assignable. The reason that auto_ptr causes so much trouble is precisely because it doesn't follow normal copy and assignment semantics. Naturally, anything that's const is not going to be assignable. So, you can't stick const anything in a standard container. And if the element isn't const, then you are going to be able to change it.
The closest solution that I believe is possible would be to use an indirection of some kind. So, you could have a pointer to const or you could have an object which holds the value that you want but the value can't be changed within the object (like you'd get with Integer in Java).
Having the element at a particular index be unchangeable goes against how the standard containers work. You might be able to construct your own which work that way, but the standard ones don't. And none which are based on arrays will work regardless unless you can manage to fit their initialization into the {a, b, c} initialization syntax since once an array of const has been created, you can't change it. So, a vector class isn't likely to work with const elements no matter what you do.
Having const in a container without some sort of indirection just doesn't work very well. You're basically asking to make the entire container const - which you could do if you copy to it from an already initialized container, but you can't really have a container - certainly not a standard container - which contains constants without some sort of indirection.
EDIT: If what you're looking to do is to mostly leave a container unchanged but still be able to change it in certain places in the code, then using a const ref in most places and then giving the code that needs to be able to change the container direct access or a non-const ref would make that possible.
So, use const vector<int>& in most places, and then either vector<int>& where you need to change the container, or give that portion of the code direct access to the container. That way, it's mostly unchangeable, but you can change it when you want to.
On the other hand, if you want to be able to pretty much always be able to change what's in the container but not change specific elements, then I'd suggest putting a wrapper class around the container. In the case of vector, wrap it and make the subscript operator return a const ref instead of a non-const ref - either that or a copy. So, assuming that you created a templatized version, your subscript operator would look something like this:
const T& operator[](size_t i) const
{
return _container[i];
}
That way, you can update the container itself, but you can't change it's individual elements. And as long as you declare all of the functions inline, it shouldn't be much of a performance hit (if any at all) to have the wrapper.
You can't create a vector of const ints, and it'd be pretty useless even if you could. If i remove the second int, then everything from there on is shifted down one -- read: modified -- making it impossible to guarantee that v[5] has the same value on two different occasions.
Add to that, a const can't be assigned to after it's declared, short of casting away the constness. And if you wanna do that, why are you using const in the first place?
You're going to need to write your own class. You could certainly use std::vector as your internal implementation. Then just implement the const interface and those few non-const functions you need.
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. :-(
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];
}
I'm with Noah: wrap the vector with a class that exposes only what you want to allow.
If you don't need to dynamically add objects to the vector, consider std::tr1::array.
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 ints. 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).
I've been thinking a bit on this issue and it seems that you requirement is off.
You don't want to add immutable values to your vector:
std::vector<const int> vec = /**/;
std::vector<const int>::const_iterator first = vec.begin();
std::sort(vec.begin(), vec.end());
assert(*vec.begin() == *first); // false, even though `const int`
What you really want is your vector to hold a constant collection of values, in a modifiable order, which cannot be expressed by the std::vector<const int> syntax even if it worked.
I am afraid that it's an extremely specified task that would require a dedicated class.
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.
Using just an unspecialized vector, this can't be done. Sorting is done by using assignment. So the same code that makes this possible:
sort(v.begin(), v.end());
...also makes this possible:
v[1] = 123;
You could derive a class const_vector from std::vector that overloads any method that returns a reference, and make it return a const reference instead. To do your sort, downcast back to std::vector.
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.
Compilation fails because push_back() (for instance) is basically
underlying_array[size()] = passed_value;
where both operand are T&. If T is const X that can't work.
Having const elements seem right in principle but in practice it's unnatural, and the specifications don't say it should be supported, so it's not there. At least not in the stdlib (because then, it would be in vector).