Назначение контейнера 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.