2009-05-23 2 views
10

компилируется: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, если только мне это не нужно.

ответ

44

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

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

v2.assign(v1.begin(), v1.end()); 
+2

Почему? Я бы понимал, что не решаюсь о неявно преобразовании вектора в вектор , но int * to const int *? Я думал, что в этом отношении особое внимание уделяется соседу. Любая идея, почему стандарт C++ решил против нее? –

+0

Возможно, что-то, что связано с шаблонами, точно соответствует, а не всегда самым удобным. – user7116

+10

Я видел этот пример где-то: яблоко - это плод, но сумка из яблок - это не мешочек с фруктами. Это нарушило бы принцип ответственности Лискова: вы можете поместить Оранжевый в Сумку с фруктами, но вы не можете поместить Оранжевый в ящик яблок. Если Bag (или, в вашем случае, вектор ) были неизменными, у вас не было бы этой проблемы. –

7

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

Это, пожалуй, легче увидеть в следующем коде:

#include <vector> 
using namespace std; 

int main() { 
    vector <char> cv; 
    vector <int> iv; 
    cv = iv; // error 
} 
20

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

3

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

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

где T представляет тип элемента всего класса, в то время как любой типа, присваиваемые Т.

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

4

В 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 не приходит с ним двигаться конструкторами, это будет очень плохо производительность мудрым.

1

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

2

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

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

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

2

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

template<class T> 
class Test 
{ 
    T t; 
}; 

template<> 
class Test<const int> 
{ 
    char array[1000]; 
}; 

Таким образом, Test<const int> содержит массив символов, в то время как Test<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)

Смежные вопросы