Reputation: 10055
Assuming this code:
class Parent {}
class Child : public Parent {}
static std::vector<std::unique_ptr<Child>> Foo();
Is there a simpler way to write this function:
std::vector<std::unique_ptr<Parent>> Bar() {
auto children = Foo();
std::vector<std::unique_ptr<Parent>> parents;
result.insert(result.end(), std::make_move_iterator(children.begin()),
std::make_move_iterator(children.end()));
return parents;
}
This doesn't work:
std::vector<std::unique_ptr<Parent>> Bar() {
return Foo(); // Compiler error: cannot convert from vector<...> to vector<...>
}
Upvotes: 3
Views: 580
Reputation: 477100
Several "simpler" ways:
#include <algorithm>
#include <iterator>
std::vector<std::unique_ptr<Base>> f1(std::vector<std::unique_ptr<Derived>> v)
{
std::vector<std::unique_ptr<Base>> result;
result.reserve(v.size());
std::move(v.begin(), v.end(), std::back_inserter(result));
return result;
}
std::vector<std::unique_ptr<Base>> f2(std::vector<std::unique_ptr<Derived>> v)
{
return {std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())};
}
Upvotes: 2
Reputation: 69892
Suggest you use a handle/body idiom and implement the polymorphism as an implementation detail of the handle class.
This gives you value semantics (works in containers) and also allows you to implement relational operators easily:
#include <vector>
#include <memory>
class ParentImpl {
public:
virtual ~ParentImpl() = default;
virtual void foo() {}
};
class ChildImpl : public ParentImpl {};
class ParentHandle
{
public:
using ptr_type = std::unique_ptr<ParentImpl>;
// construct from ptr_type
ParentHandle(ptr_type ptr = nullptr) : ptr_(std::move(ptr_)) {}
// public interface defers to polymorphic implementation
void foo()
{
ptr_->foo();
}
private:
std::unique_ptr<ParentImpl> ptr_;
};
static std::vector<ParentHandle> Foo()
{
std::vector<ParentHandle> result;
result.emplace_back(std::make_unique<ParentImpl>());
result.emplace_back(std::make_unique<ChildImpl>());
return result;
}
Upvotes: 1
Reputation: 275480
Well we can write boilerplate elsewhere:
templace<class Cin>
struct move_from_c{
Cin* c;
template<class Cout>
operator Cout()&&{
using std::begin; using std::end;
return {std::make_move_iterator(begin(*c)), std::make_move_iterator(end(*c))};
}
};
template<class C, class dC=std::remove_reference_t<C>>
move_from_c<dC> move_from(C&&c){
return {std::addressof(c)};
}
And then your function is:
std::vector<std::unique_ptr<Parent>> Bar() {
return move_from(Foo());
}
This splits details of implementation from business logic of Bar
. (How the move from is done is split from the decision to move from).
Upvotes: 3
Reputation: 21576
The types are different. Foo()
returns std::vector<std::unique_ptr<Child>>
while Bar()
returns std::vector<std::unique_ptr<Parent>>
. There's no way to circumvent that. However, rather than:
std::vector<std::unique_ptr<Parent>> Bar() {
auto children = Foo();
std::vector<std::unique_ptr<Parent>> parents;
result.insert(result.end(), std::make_move_iterator(children.begin()),
std::make_move_iterator(children.end()));
return parents;
}
You can do:
std::vector<std::unique_ptr<Parent>> Bar() {
auto tmp = Foo();
return {std::make_move_iterator(tmp.begin()), std::make_move_iterator(tmp.end()));}
}
Upvotes: 4