Копирование вектора> в вектор> (разные случаи) C++

у меня:

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

которые я хотел бы скопировать в

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

теперь я заметил, что если я это сделаю:

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;
};

он компилируется отлично (clang++ std==c++14), но если я это сделаю:

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

Я нахожу странным, что когда я использую конструктор копирования, он не работает, потому что он не может понять преобразование из non-const в const?

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

может кто-нибудь объяснить, почему, пожалуйста, и если так, как я это делаю (используя итератор в конструктор) является лучшим решением?

2 ответов


сначала шаблон класса, созданный с разными типами, является совершенно другим типом. Тогда std::shared_ptr<int> и std::shared_ptr<const int> совершенно разные типы, и std::vector<std::shared_ptr<int>> и std::vector<std::shared_ptr<const int>> также являются разными типами и не могут быть преобразованы друг в друга.

по словам конструкторы of std::vector, конструктор копирования (5-й) принимает std::vector С таким же типом в качестве параметра. Это означает для std::vector<std::shared_ptr<const int>>, это не может занять std::vector<std::shared_ptr<int>>, который не может быть преобразован в std::vector<std::shared_ptr<const int>> неявно.

С другой стороны, конструктор, принимающий диапазон итератора (4-й), является шаблоном функции, тип итератора-параметр шаблона, который не должен быть итератором, указывающим на тот же тип. Разрешено быть итератором, указывающим на другой тип, если этот тип может использоваться для построения вектора. std::shared_ptr<int> может использоваться для построения std::shared_ptr<const int>, тогда все в порядке.

отметим, что std:: shared_ptr есть копировать / переместить шаблоны конструкторов, которые могут принимать std::shared_ptr С различным типом элемента в качестве аргумента. (А std::vector нет.)


ваш код может работать, если std::vector при условии преобразования конструктор:

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())
    {}

    ...
};

но наличие такого конструктора в каждом стандартном контейнере библиотеки не добавляет слишком много значения, потому что почти такой же эффект может быть достигнут путем введения еще более общего назначения container_cast утилиты (см., например, ответ). Тогда вы могли бы написать:

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