2016-10-28 4 views
0

Я реализую пользовательский вектор указателей my_ptr_vector.Сделать контейнер covariant

У меня есть класс Base и Derived, получающий Base.

У меня есть метод, который должен действовать (по ссылке const!) На обоих my_ptr_vector<Base> и my_ptr_vector<Derived>. Конечно, он только ссылается на методы элементов из класса Base.

Однако компилятор жалуется, что он не имеет способа преобразования my_ptr_vector<Derived> в my_ptr_vector<Base>.

Minimal пример воспроизведения проблемы:

#include <vector> 
#include <memory> 

class Base {}; 
class Derived : public Base {}; 

template<typename Element> 
class my_ptr_vector : public std::vector< std::unique_ptr<Element> > {}; 

void funct(const my_ptr_vector<Base>& vect) {} 

int main() 
{ 
    my_ptr_vector<Derived> vect; 
    funct(vect); 
} 

ошибка:

no suitable user-defined conversion from "my_ptr_vector<Derived>" to "const my_ptr_vector<Base>" exists 

Я нашел here, что я мог бы сделать его работу, если я предоставил оператор конструктора и назначения из my_ptr_vector<U>, с U общий, так что U* может быть преобразован в T*.

Действительно, если в примере изменить класс к этому, он работает

template<typename Element> 
class my_ptr_vector : public std::vector< std::shared_ptr<Element> > { 
public: 
    my_ptr_vector() {} 

    ///copy constructor from vector of pointers to generic U 
template<typename DerivedElement> 
    my_ptr_vector(const my_ptr_vector<DerivedElement>& oth) 
    { 
     printf("Oh, noes!"); //we don't want this method executed! 

     resize(oth.size()); 

     for (std::shared_ptr<Element> ptr : oth) 
     { 
      push_back(ptr); 
     } 
    } 
}; 

Однако ли выполнить print заявление в конструкторе -это не просто намек, что он не должен беспокоиться ; он фактически выполняет преобразование!

Есть ли способ избежать этого?

Другим возможным решением является, конечно, сделать func шаблонный:

template<typename T> 
    void funct(const my_ptr_vector<T>& vect) {} 

Однако, в этом случае я потеряю информацию, что внутри func, элементы vect всегда являются типа Base.

+2

Проще, если вы укажете нам код ([mcve]). Моя первая мысль заключается в использовании 'my_ptr_vector ', что является обычным способом обработки векторов классов, некоторые из которых могут быть получены. –

+0

Возможно, вы ищете старый добрый [std :: vector] (http://en.cppreference.com/w/cpp/container/vector) из [std :: unique_ptr] (http: //en.cppreference. com/w/cpp/memory/unique_ptr) или [std :: shared_ptr] (http://en.cppreference.com/w/cpp/memory/shared_ptr)? –

+0

@ ТопологическийСорт вы правы, сделано :) –

ответ

0

Это похоже на то, что вы хотите. Вторая часть кода, копия ctor, не нуждается в изменении.

Я не думаю, что вы можете уйти от необходимости бросать на std::unique_ptr. Он хочет этого, даже если он нажимает Base*.

#include <vector> 
#include <memory> 

class Base {}; 
class Derived : public Base {}; 

template<typename Element> 
class my_ptr_vector : public std::vector< std::unique_ptr<Element> > {}; 

void funct(const my_ptr_vector<Base>& vect) {} 

int main() 
{ 
    my_ptr_vector<Base> vect; 
    vect.push_back(std::unique_ptr<Base>(new Derived)); 

    funct(vect); 
} 
+0

Да это компилируется; но я потерял бы возможность вызвать Derived-only методы, и мне это нужно. –

+0

@FrancescoDondi no вы бы этого не сделали - это то, что 'dynamic_cast' /' static_cast' было сделано для ... –

+0

Mhh да, вы правы, но это уродливо. Вместо того, чтобы помнить внутри 'func', что тип' Base', а не 'T', я должен помнить, что тип' Derived' не 'Base' ... то, что я хочу, это сдвинуть тип- проверка onus на компиляторе. –

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