Назначение контейнера STL и указатели const - PullRequest
10 голосов
/ 24 мая 2009

Это компилируется:

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!

Каковы правила эквивалентности типов для вложенных указателей const? Я думал, что преобразование будет неявным. Кроме того, я бы предпочел не осуществлять поэтапное назначение контейнеров STL, если только мне это не нужно.

Ответы [ 8 ]

43 голосов
/ 24 мая 2009

Прямое назначение невозможно. Как объяснили другие, эквивалентность устанавливается не типами указателей, а типами контейнеров. В этом случае vector не хочет принимать другой вектор, имеющий другой, но совместимый тип элемента.

Никаких проблем, поскольку вы можете использовать функцию-член assign:

v2.assign(v1.begin(), v1.end());
20 голосов
/ 24 мая 2009

Преобразование из int* в const int* встроено в язык, но векторы их не имеют автоматического преобразования из одного в другое.

7 голосов
/ 24 мая 2009

Проблема не в указателях, а в типах двух векторов. В вашем примере нет стандартных преобразований между шаблонными типами, такими как типы v1 и v2.

Возможно, это легче увидеть в следующем коде:

#include <vector>
using namespace std;

int main() {
    vector <char> cv;
    vector <int> iv;
    cv = iv;    // error
}
4 голосов
/ 24 июля 2009

В шаблонных классах C ++ каждый экземпляр шаблона представляет собой совершенно другой класс - между 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);

К сожалению, пока в C ++ 0x не появятся конструкторы перемещения, это будет довольно плохо с точки зрения производительности.

3 голосов
/ 24 мая 2009

Было бы вполне возможно написать свою собственную версию vector, где это было бы возможно. Он будет идентичен стандартному типу, но с шаблонной версией operator=, что-то вроде этого:

template <class A>
vector2<T> &operator=(const vector2<A> &other)
{
    assign(other.begin(), other.end());
    return *this;
}

Где T - тип элемента всего класса, а A - любой тип, назначаемый T.

Мне не понятно, почему у std::vector этого нет.

2 голосов
/ 23 октября 2011

Важным моментом, не упомянутым ни в одном из предыдущих ответов, является то, что специализации шаблонов делают это невозможным для реализации на уровне языка. Рассмотрим:

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)

2 голосов
/ 28 июля 2009

Опасно, если вы не знаете, что типы абсолютно совместимы:

v2 = reinterpret_cast<std::vector<const int *> & >(v1);

В большинстве реализаций STL используется специализация, в которой все векторы указателей имеют одинаковую базовую реализацию. Это связано с тем, что (void *) обычно имеет тот же размер, что и (int *), или любой другой тип указателя.

1 голос
/ 28 июля 2009

Принуждение по шаблону участника идиома - один из возможных подходов к решению проблемы. По существу, добавлен оператор копирования-присваивания шаблона члена, который позволяет классу шаблона участвовать в тех же неявных преобразованиях типов (принуждении), которые в противном случае возможны только для параметров типа шаблона класса. Хотя идиома используется в STL в других местах, она не доступна в std :: vector.

...