Назначение контейнера STL и константные указатели
Это компилируется:
int* p1;
const int* p2;
p2 = p1;
Это не означает:
vector<int*> v1;
vector<const int*> v2;
v2 = v1; // Error!
v2 = static_cast<vector<const int*> >(v1); // Error!
Каковы правила эквивалентности типов для вложенных указателей констант? Я думал, что обращение будет неявным. Кроме того, я бы предпочел не применять точечное назначение контейнеров STL, если только мне это не нужно.
Ответы
Ответ 1
Прямое назначение невозможно. Как объяснили другие, эквивалентность не определяется типами указателей, а типами контейнеров. В этом случае вектор не хочет принимать другой вектор, который имеет другой, но совместимый тип элемента.
Нет реальной проблемы, так как вы можете использовать функцию члена assign
:
v2.assign(v1.begin(), v1.end());
Ответ 2
Преобразование из int*
в const int*
встроено в язык, но векторы из них не имеют автоматического преобразования из одного в другое.
Ответ 3
Проблема заключается не в указателях, а в типах двух векторов. Стандартных преобразований между шаблонами типа v1 и v2 в вашем примере нет.
Это, возможно, проще увидеть в следующем коде:
#include <vector>
using namespace std;
int main() {
vector <char> cv;
vector <int> iv;
cv = iv; // error
}
Ответ 4
В шаблонах с шаблоном С++ каждый экземпляр шаблона является совершенно другим классом - разница между vector<int *>
и vector<const int *>
равна разнице между vector<int *>
и vector<string>
или любыми другими двумя классами для этого дело.
Возможно, что комитет мог бы добавить оператора преобразования на vector
в vector<U>
, поскольку Earwicker предлагает - и вы можете идти вперед и предоставлять свои собственные реализация такой функции:
template <class A, class T>
vector<T> convert_vector(const vector<A> &other)
{
vector<T> newVector;
newVector.assign(other.begin(), other.end());
return newVector;
}
и используйте его так:
vector<int*> v1;
vector<const int*> v2;
v2 = convert_vector<const int*>(v1);
К сожалению, до тех пор, пока С++ 0x не придет с этим движением конструкторов, это будет довольно плохой по производительности.
Ответ 5
Было бы вполне возможно написать собственную версию vector
, где это было возможно. Он был бы идентичен стандартным типам, но с шаблонизированной версией operator=
, примерно так:
template <class A>
vector2<T> &operator=(const vector2<A> &other)
{
assign(other.begin(), other.end());
return *this;
}
Где T - тип элемента всего класса, тогда как A - любой тип, назначаемый T.
Мне непонятно, почему std::vector
не имеет этого.
Ответ 6
Опасно, если вы не знаете, что типы абсолютно совместимы:
v2 = reinterpret_cast<std::vector<const int *> & >(v1);
В большинстве реализаций STL используется специализация: все векторы указателей используют одну и ту же базовую реализацию. Это происходит потому, что (void *) обычно имеет тот же размер, что и (int *) или любой другой тип указателя.
Ответ 7
Важным моментом, который не упоминается ни в одном из предыдущих ответов, является то, что специализированные шаблоны делают это невозможным для реализации на основе языка. Рассмотрим:
template<class T>
class Test
{
T t;
};
template<>
class Test<const int>
{
char array[1000];
};
Таким образом, Test<const int>
содержит массив символов, тогда как Test<int>
содержит
один 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;
}
В действительности vector<foo *>
и vector<const foo *>
могут
все - в частности, они могут иметь одинаковый размер. Однако, возможность
явной специализации шаблонов означает, что они могут отличаться
эффектно, следовательно, нежелание компилятора разрешить преобразование.
(Этот ответ в основном копируется из http://bytes.com/topic/c/answers/449611-cast-vector-foo-vector-const-foo#post1717570)
Ответ 8
Принуждение по шаблону участника Идиома - один из возможных подходов к решению проблемы. По сути, добавляется оператор присваивания экземпляра шаблона члена, который позволяет классу шаблона участвовать в тех же неявных преобразованиях типа (принуждения), которые в противном случае возможны только в параметрах типа шаблона класса. Хотя идиома используется в STL в других местах, она недоступна в std::vector.