I have a question regarding polymorphism and maybe other techniques. Consider the following scheme:
#include <vector>
#include <memory>
using namespace std;
struct Base
{ };
struct Derived : Base
{ };
class group
{
private:
vector< unique_ptr<Base> > V;
public:
group( /* what to put here? */ )
: V( /* again: how to construct V? */ )
{ }
}
Here, I have three classes: a base class, called Base
; a derived class, called Derived
; and a last class, group
, that would act as a wrapper to hold Base
pointers. But I'd like to achieve the following:
Use move semantics. There should be no copies involved. The caller should be able to give the constructor several temporaries, as the constructor would steal them:
group my_wonderful_group( Base( /* parameters */ ) , Derived ( /* ... */ ) , Derived ( /* ... */ ) );
Initialize
V
in the initialization list. That way,V
could be const-qualified (despite all the other benefits initializing member objects in initialization lists carries).
I've tried several things, but they either do not seem appropiate, or are simply conceptually far from my goals:
initializer_list
s' elements are non-movable;unique_ptr
s are movable-only.- Variadic templates do not seem capable to fit the goal of making
V
const. Asinitializer_list
s can't hold objects of different types (just likevector
s), I first thought about them, but, how? After reading many examples, I still can't figure out how to make a variadic template constructor, or even if it's possible to do so without a workaround (i.e.: creating some init() function that takes aBase
, aDerived
,... and plays with it). - Create a function that returns
unique_ptr<Base>
and that forwards its arguments to the constructor ofDerived
, thus acting as an user-friendly wrapper to thegroup
class. This does, however, make little sense, as I illustrate with the code attached below.
This is what I have:
#include <string>
#include <vector>
#include <memory>
#include <initializer_list>
#include <iostream>
using namespace std;
struct Base
{
string s;
Base(Base && b) : s(move(b.s)) { }
Base(const string & S) : s( S ) { }
};
struct Derived : Base
{
Derived(const string & S) : Base( S ) { }
};
unique_ptr<Base>
BASE ( const string & S )
{
return unique_ptr<Base>( new Base(S) );
}
unique_ptr<Base>
DERIVED ( const string & S )
{
return unique_ptr<Base>( new Derived(S) );
}
class C
{
private:
vector< unique_ptr<Base> > V;
public:
template<typename ... T>
C
( T ... t ) : V({ t... })
{ }
void
print
( void )
{
for ( const auto & x : this->V )
cout << x->s << endl;
}
;
};
int main(void)
{
C c( BASE("hola") , DERIVED("der1") , DERIVED("bor3") );
c.print();
return 0;
}
It complains, however, about the usage of the [deleted] copy constructor of unique_ptr
being called, when the argument pack in the constructor of group
is expanded and comma-separated put into the initializer_list
that would be used to initialize V
.
I guess that my question goes down to a vector
, and, in fact, could be applied to one: vector<unique_ptr<Base>>( /* initialize with derived classes */ )
. I think this must have been solved before, as polymorphism is basic C++, and holding objects of derived classes seems a very common usage of it. As a note, I use g++ 4.8.1
.
Thanks in advance. Best regards, Kalrish
P.S.: I've just read this question which seems to partly cover my problem.