This compiles:
int* p1;
const int* p2;
p2 = p1;
This does not:
vector v1;
vector v2;
v2 = v1;
Dangerous, unless you know the types are absolutely compatible:
v2 = reinterpret_cast<std::vector<const int *> & >(v1);
Most STL implementations do use a specialization were all vectors of pointers share the same underlying implementation. This is since (void *) is typically the same size as (int *) or any other pointer type.
An important point not mentioned in any of the previous answers is that template specializations make this impossible to implement on a language-wide bases. Consider:
template<class T>
class Test
{
T t;
};
template<>
class Test<const int>
{
char array[1000];
};
Thus Test<const int>
contains an array of chars, whereas Test<int>
contains
a single int.
#include <iostream>
using namespace std;
int main()
{
Test<int> t1;
Test<const int> t2;
cout << sizeof(t1) << endl; // gives 4
cout << sizeof(t2) << endl; // gives 1000
return 0;
}
In reality vector<foo *>
and vector<const foo *>
may hardly differ at
all --- in particular, they may have the same size. However, the possibility
of explicit template specialization means that they could differ
spectacularly, hence the reluctance of the compiler to allow conversion.
(This answer is mostly copied from http://bytes.com/topic/c/answers/449611-cast-vector-foo-vector-const-foo#post1717570)
Coercion by Member Template idiom is one possible approach to solve the problem. Essentially, a member template copy-assignment operator is added that allows the template class to participate in the same implicit type conversions (coercion) that are otherwise possible only on the type parameters of the class template. Although the idiom is used in the STL in other places, it is not available in std::vector.
It would be perfectly possible to write your own version of vector
where this was possible. It would be identical to the standard type, but with a templated version of operator=
, something like this:
template <class A>
vector2<T> &operator=(const vector2<A> &other)
{
assign(other.begin(), other.end());
return *this;
}
Where T is the element type of the whole class, whereas A is any type assignable to T.
It's not clear to me why std::vector
doesn't have this.
Direct assignment is not possible. As others explained, the equivalence is not established by the pointer types, but by the container types. In this case, vector doesn't want to accept another vector that has a different, but compatible element type.
No real problem, since you can use the assign
member function:
v2.assign(v1.begin(), v1.end());
In C++ templated classes, each instantiation of the template is a completely different class - there is as much difference between vector<int *>
and vector<const int *>
as there is between vector<int *>
and vector<string>
or any other two classes for that matter.
It is possible that the committee could have added a conversion operator on vector
to vector<U>
as Earwicker suggests - and you can go ahead and provide your own implementation of such a function:
template <class A, class T>
vector<T> convert_vector(const vector<A> &other)
{
vector<T> newVector;
newVector.assign(other.begin(), other.end());
return newVector;
}
and use it like so:
vector<int*> v1;
vector<const int*> v2;
v2 = convert_vector<const int*>(v1);
Unfortunately, until C++0x comes with it's move constructors, this will be pretty bad performance-wise.