I am trying to initialize a collection of pointers to class A
through an initializer list. However, the initializer list cannot use reference as a template type.
I have the following code.
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <memory>
struct A
{
virtual void f() const noexcept { std::cout << "A"; }
};
struct B : public A
{
virtual void f() const noexcept override { std::cout << "B"; }
};
class Test
{
std::vector<std::shared_ptr<A>> vec;
public:
Test(const std::initializer_list<A>& list)
//Test(const std::initializer_list<A&>& list) <------ Solution?
{
for (auto& x : list)
vec.push_back(std::make_shared<A>(x));
}
void print()
{
std::for_each(vec.begin(), vec.end(), [](auto x) { x->f(); });
}
};
int main()
{
Test test = { A(), B() };
test.print();
}
The code prints:
AA
It should print:
AB
Is there a simple way to do this, without having to create pointers in the calling method?
The related article (How do I implement polymorphism with std::shared_ptr?) did not provide much help with this problem.
std::initializer_list<T>
holds the passed objects by value, so there can be no polymorhism. Also std::make_shared<A>
always makes an object of type A
, not some type that derives from A
. You need another approach.
Since you have an arbitrary number of arguments with arbitrary types, you'll probably need a variadic template constructor.
Edit: My code suggestion was way too complicated. The comment by WhozCraig is much better:
template<class... Args> Test(Args&&... args) : vec { std::make_shared<std::remove_reference_t<Args>>(std::forward<Args>(args))... } { }
You are inserting to the vector using std::make_shared<A>()
. You are copying a bunch of B
and A
into a bunch of A
.
If you want the syntax in your main to work, the simplest way to do that is a template :
struct Foo {
template<typename... Args>
Foo(Args... args) :
vec{std::make_shared<Args>(std::move(args))...}
{}
private:
std::vector<std::shared_ptr<A>> vec;
};
You're making new shared_ptr
s on the following line
vec.push_back(std::make_shared<A>(x));
It doesn't matter what x
was, you made a new A
with its values.
You probably want to create a shared_ptr<A>
and pass the pointer from x.get()
to the new empty shared_ptr<A>
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