I created this class, which represents a set of shapes:
class CompoundShape : public Shape {
private:
std::vector<std::unique_ptr<Shape>> shapes;
public:
CompoundShape(std::initializer_list<Shape *> shapes) : shapes(shapes) {}
void draw() {
for_each(shapes.begin(), shapes.end(), [](auto &shape) { shape->draw(); });
}
};
The class Shape
has another child class, SimpleShape
. Ideally, I'd want to initialize a CompoundShape
like this, without having to worry about freeing the pointers to the shapes afterwards:
CompoundShape shape = {
new SimpleShape(...),
new SimpleShape(...),
new CompoundShape{...},
...
}
The only problem, I think, is in the CompoundShape
constructor, where I try to do shapes(shapes)
which of course doesn't work, because a std::vector<std::unique_ptr<Shape>>
can't be initialized with a std::initializer_list<Shape *> shapes
.
What would be the best way of achieving this conversion?
Sad that we cannot use std::initializer_list<std::unique_ptr<Shape>>
.
You can still use constructor of vector taking 2 iterators to do the (not so explicit) conversion:
CompoundShape(std::initializer_list<Shape *> shapes) : shapes(shapes.begin(), shapes.end()) {}
vector constructor would do something similar to
template <typename T>
template <typename It> // SFINAE to avoid to conflict with vector(std::size_t, T) when T=size_t
std::vector<T>::vector<T>(It begin, It end) :
m_size(std::distance(begin, end)),
m_capacity(m_size),
m_data(allocate<T>(m_size))
{
std::size_t i = 0;
for (auto it = begin; it != end; ++it, ++i) {
new (&data[i]) T(*it); // placement new, calling constructor deferencing iterator
}
}
So in your case
std::initializer_list<Shape *>::iterator it /* = .. */;
Shape* shape = *it;
new (&data[i]) std::unique_ptr<Shape>(shape);