I need to dynamically create instances of an Aggregate
class in C++ which inherits from multiple base classes, where the combination of base classes can vary based on runtime conditions. I want to avoid pre-populating all possible combinations.
Here's a simplified version of what I'm trying to achieve
I have several base classes:
class CharBase
{
CharBase() { std::cout << "CharBase\n"; }
};
class UnsignedCharBase
{
UnsignedCharBase() { std::cout << "UnsignedCharBase\n"; }
};
class ShortBase
{
ShortBase() { std::cout << "ShortBase\n"; }
};
class IntBase
{
IntBase() { std::cout << "IntBase\n"; }
};
I use the following Aggregate
class template to inherit from multiple base classes
template<typename... Bases>
class Aggregate : Bases…
{
Aggregate() { std::cout << "Aggregate\n"; }
};
My goal is to create instances of the Aggregate
classes on demand based on runtime conditions. The expected result is to create an Aggregate
instance as if I hardcoded it, for example:
new Aggregate<CharBase, UnsignedCharBase, ShortBase>
new Aggregate<UnsignedCharBase, IntBase>
One way to turn runtime value to compile value is to use std::variant
.
For your case, I would use std::tuple
to store the result for "optional" type.
template <typename T>
std::variant<std::tuple<>,
std::tuple<std::type_identity<T>>>
AsOptionalTypeVar(bool b)
{
if (b) {
return std::tuple<std::type_identity<T>>{};
} else {
return std::tuple<>{};
}
}
An Helper trait to transform a tuple into Aggregate
template <typename T> struct to_aggregate;
template <typename... Ts> struct to_aggregate<std::tuple<std::type_identity<Ts>...>>
{
using type = Aggregate<Ts...>;
};
Then you might let std::visit
does the Cartesian product
std::visit(
[](auto... bases){
using all_base = decltype(std::tuple_cat(bases...));
using aggregate = typename to_aggregate<all_base>::type;
// Use aggregate type as you want
},
AsOptionalTypeVar<CharBase>(useCharBase),
AsOptionalTypeVar<UnsignedCharBase>(useUnsignedCharBase),
AsOptionalTypeVar<ShortBase>(useShortBase),
AsOptionalTypeVar<IntBase>(useIntBase)
);