What is the proper way to allow vectors of shared pointers to a derived class to get passed to a function which is expecting a vector of shared pointers to a base class without performing a copy?
Here is the code:
#include <string>
#include <vector>
#include <memory>
class Base {
public:
std::string Name;
};
using BaseList = std::vector<std::shared_ptr<Base>>;
class Derived : Base {
};
using DerivedList = std::vector<std::shared_ptr<Derived>>;
class BaseHandler {
public:
void process( BaseList list ) {
}
};
int main() {
DerivedList list;
BaseHandler bh;
bh.process( list );
}
Code Link: http://coliru.stacked-crooked.com/a/5a5b18ba3b2a4f08
EDIT: DOH!!! I posted the wrong one. Sorry about that...here is the shared_ptr one.
You may try this.
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; }
The key ideas are:
Follow up:
Conversion from "container of shared pointer to derived class" to "container of shared pointer to base class" is possible and not very difficult. However, I concern whether the design choice of using "container of shared pointer to base class" will give you acceptable performance.
Let's discuss how to do it first.
std::shared_ptr<Base> object from each std::shared_ptr<Derived> object by using std::static_pointer_cast.std::static_pointer_cast on everything entries of the list, we can use std::transform.So, the code looks like:
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);
Or:
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);
}
};
However, this approach has quite a lot of performance penalty.
I suggest you to evaluate the performance to see whether this approach is acceptable. Otherwise, it is better to consider some other design choices.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With