Вы можете попробовать это.
template <class T,
class SharedPtr = typename T::value_type,
class Element = typename SharedPtr::element_type,
class IsDerived = typename std::enable_if<std::is_base_of<Base, Element>::value, void*>::type
>
void process(const T& t) { std::cout << "process" << std::endl; }
Ключевые идеи:
- Вместо того, чтобы доступ к элементам с помощью указателей базового класса, мы можем получить доступ к их через конкретную информацию типа, известный компилятор.
- Этот шаблон функции использует трюк под названием «SFINAE», чтобы проверить, является ли этот параметр контейнером интеллектуального указателя производного класса.
Последующие:
Преобразование из «контейнера общего указателя на производный класс» в «контейнер общего указателя на базовый класс» можно и не очень сложно. Однако я отношусь к тому, что выбор дизайна использования «контейнера общего указателя на базовый класс» даст вам приемлемую производительность.
Давайте обсудим, как это сделать в первую очередь.
- Мы можем создать
std::shared_ptr<Base>
объект из каждого std::shared_ptr<Derived>
объекта с помощью std::static_pointer_cast
.
- Чтобы применить
std::static_pointer_cast
по всем пунктам списка, мы можем использовать std::transform
.
- Если у вас есть много производных классов, преобразование может быть доступно для всех производных классов, используя шаблон функции с проверкой SFINAE, как указано.
Итак, код выглядит следующим образом:
DerivedList derivedList;
// Put items into derivedList
BaseList baseList;
baseList.reserve(derivedList.size());
std::transform(std::begin(derivedList), std::end(derivedList), std::back_inserter(baseList),
[](const std::shared_ptr<Derived>& shptr)
{
return std::static_pointer_cast<Base>(shptr);
});
BaseHandler bh;
bh.process(baseList);
Или:
class BaseForwarder
{
public:
template <class T,
class SharedPtr = typename T::value_type,
class Element = typename SharedPtr::element_type,
class IsDerived = typename std::enable_if<std::is_base_of<Base, Element>::value, void*>::type
>
void process(const T& derivedList)
{
BaseList baseList;
baseList.reserve(derivedList.size());
std::transform(std::begin(derivedList), std::end(derivedList), std::back_inserter(baseList),
[](const SharedPtr& shptr)
{
return std::static_pointer_cast<Base>(shptr);
});
BaseHandler bh;
bh.process(baseList);
}
};
Однако этот подход имеет довольно много потерь производительности.
- Новый список указателей на базовый класс должен быть создан для каждого списка указателей на производный класс. Новый график содержит много времени и памяти.
- Доступ к объектам осуществляется с помощью указателей. Эта косвенность замедляет работу.
- Поскольку объекты не распределены в компактную структуру данных, промахи кэша будут серьезными.
Предлагаю вам оценить производительность, чтобы убедиться, что этот подход является приемлемым. В противном случае лучше рассмотреть некоторые другие варианты дизайна.
Я не вижу общих указателей. –
Нет способа, правильного или иного. –
Копия чего? Из 'std :: shared_ptr'? Это не так много копировать их (их общее состояние не сильно скопировано кстати). – vsoftco