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_ptrs 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