2016-09-01 27 views
7

mam:Kopiowanie wektor <shared_pt<T>> do wektora <shared_ptr <const T>> (różne przypadki) C++

std::vector<std::shared_ptr<T>> 

której chciałbym skopiować do

std::vector<std::shared_ptr<const T>> 

Teraz zauważyłem, że jeśli to zrobić:

class A 
{ 
public: 
    A(const std::vector<std::shared_ptr<int>>& list) : internalList(list.begin(), list.end()) {} 
    std::vector<std::shared_ptr<const int>> internalList; 
}; 

kompiluje grzywny (szczęk ++ std == C++ 14), ale jeśli mam zrobić:

class A 
{ 
public: 
    A(const std::vector<std::shared_ptr<int>>& list) : internalList(list) {} 
    std::vector<std::shared_ptr<const int>> internalList; 
}; 

Uważam, że to dziwne, że kiedy używam konstruktora kopiowania, to nie działa, ponieważ nie może wymyślić konwersji z const do const?

xxxx.cpp:672:56: error: no matching constructor for initialization of 'std::vector<std::shared_ptr<const int> >' 

Może ktoś wyjaśnić, dlaczego proszę, a jeśli tak, jak to zrobić (za pomocą iteratora w konstruktorze) jest najlepszym rozwiązaniem?

+1

Byłoby dobrze, gdyby było * tylko * konwersją z nie-const na const (tj. 'Int' na' const int'). Jednak to nie jest to, co się tutaj dzieje, to konwersja z obiektu jednego typu na obiekt zupełnie innego typu. Konstruktor kopiowania przyjmuje jako argument tylko własny typ, a nie inny typ. –

+0

Czy to ma sens, ale czy coś takiego nie działa? 'int a = 1; const int b = a'? Więc moje pytanie brzmi: dlaczego to zadanie działa i dlaczego nie można tego zrobić za pomocą konstruktora kopii? Jestem naprawdę ciekawy, co powstrzymuje to przed zrobieniem tego? Zakładam, że nie jest to zrobione z powodów optymalizacji ... – user18490

+1

@ user18490 'const std :: vector ' nie jest tym samym, co 'std :: vector '. Stąd nie ma analogii do "int" i "const int". –

Odpowiedz

2

Na początku szablon klasy utworzony za pomocą różnych typów jest zupełnie inny. Następnie są to zupełnie różne typy, a std::vector<std::shared_ptr<int>> i std::vector<std::shared_ptr<const int>> również są różnymi typami i nie mogą być konwertowane na siebie.

Zgodnie z constructors z std::vector, konstruktor kopiowania (piąty) pobiera std::vector z tego samego typu co jego parametr. Oznacza to, że w przypadku std::vector<std::shared_ptr<const int>> nie można uzyskać std::vector<std::shared_ptr<int>>, której nie można w domyśle przekształcić w std::vector<std::shared_ptr<const int>>. Z drugiej strony konstruktor przyjmujący zakres iteratora (czwarty) jest szablonem funkcji, typem iteratora jest parametr szablonu, który nie musi być iteratorem wskazującym na ten sam typ. Dozwolony jest iterator wskazujący na inny typ, jeśli ten typ może być użyty do konstrukcji wektora. std::shared_ptr<int> może być użyty do skonstruowania std::shared_ptr<const int>, to jest w porządku.

Należy pamiętać, że std::shared_ptr mają szablony konstruktorów kopiowania/przenoszenia, które mogą przyjmować std::shared_ptr z innym typem elementu jako jego argumentem. (Podczas gdy std::vector nie ma.)

3

Twój kod może działać, jeśli std::vector warunkiem konwersji konstruktora:

template<class T, class A = std::allocator<T>> 
class vector { 
public: 
    template<class T1, class A1> 
    explicit vector(const vector<T1, A1>& other) 
     : vector(other.begin(), other.end()) 
    {} 

    ... 
}; 

ale mając taką konstruktora w każdym pojemniku Biblioteka standardowa nie dodawać zbyt wiele wartości, ponieważ prawie taki sam efekt można osiągnąć poprzez wprowadzenie jeszcze bardziej ogólnego przeznaczenia narzędzie (patrz, na przykład, this answer). Wtedy możesz napisać:

class A 
{ 
public: 
    A(const std::vector<std::shared_ptr<int>>& list) : internalList(container_cast(list)) {} 
    std::vector<std::shared_ptr<const int>> internalList; 
}; 
+0

To dobre uzupełnienie powyższej odpowiedzi. Wielkie dzięki – user18490

+0

Pamiętaj, że implementacja 'container_cast' wymusza kopiowanie i nigdy się nie porusza, konieczne jest ulepszenie przed użyciem go w rzeczywistym kodzie. ; -] – ildjarn

Powiązane problemy