An attempt at a simple to-the-point answer for the rest of us.
You can't. It's broken.
Fortunately, array initializers aren't broken.
static std::unique_ptr<SerializerBase> X::x_serializers[] = {
std::unique_ptr<SerializerBase>{
new Serializer<X,int>("m_int",&X::m_int)
},
std::unique_ptr<SerializerBase>{
new Serializer<X,double>("m_double",&X::m_double)
},
nullptr, // lol. template solutions from hell possible here too.
};
If you then want to use that array to initialize a std::vector<std::unique_ptr<T>>
, there are endless ways to do so, many of which involve baroquely unpleasant template metaprogramming, all of which can be avoided with a for loop.
Fortunately, using an array instead of a std::vector works in a lot of cases where you really would have preferred to use a std::vector.
Alternately, consider writing a custom::static_vector<T>
class that take T*
's in an initializer list, and deletes them in its's destructor. Also not happy, but you need to resign yourself to the fact that std::vector<std::unique_ptr<T>>
isn't going to work in reasonable time or with reasonable effort. You can just delete any methods that do a potential move (move and copy constructors,T&operator[]()
&c). Or get fancy and implement rudimentary move semantics if you must (but you probably don't).
See [1] for a defense of this, provided for members of the Purist priesthood.
[1] Programming languages are supposed to increase productivity.
Template meta-programming isn't doing that in this case. All I
want is a way to ensure that I don't leak memory allocated in
static initialization into the heap, thereby making it impossible
to use valgrind to verify that I'm not leaking memory.
That's an everyday use-case. And it shouldn't be difficult. Making it remotely complicated only leads to shortcuts down the road.