我需要在 C++ 中动态创建
Aggregate
类的实例,该类继承自多个基类,其中基类的组合可以根据运行时条件而变化。我想避免预先填充所有可能的组合。
这是我想要实现的目标的简化版本
我有几个基类:
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"; }
};
我使用以下
Aggregate
类模板从多个基类继承
template<typename... Bases>
class Aggregate : Bases…
{
Aggregate() { std::cout << "Aggregate\n"; }
};
我的目标是根据运行时条件按需创建
Aggregate
类的实例。预期结果是创建一个 Aggregate
实例,就像我对其进行硬编码一样,例如:
new Aggregate<CharBase, UnsignedCharBase, ShortBase>
new Aggregate<UnsignedCharBase, IntBase>
这是我设法想出的解决方案。这里唯一的限制是
highestSetBit
。我试图摆脱它,但我做不到,如果有人能解决这个问题,我将不胜感激。
#include <array>
#include <iostream>
#include <memory>
#include <tuple>
class IAggregate
{
public:
virtual ~IAggregate() = default;
};
template<typename... Bases>
class Aggregate : public IAggregate, public Bases...
{
public:
Aggregate() { std::cout << "Aggregate\n"; }
virtual ~Aggregate() override = default;
};
class CharBase
{
public:
static constexpr int Mask = 1 << 0;
CharBase() { std::cout << "CharBase display\n"; }
};
class UnsignedCharBase
{
public:
static constexpr int Mask = 1 << 1;
UnsignedCharBase() { std::cout << "UnsignedCharBase display\n"; }
};
class ShortBase
{
public:
static constexpr int Mask = 1 << 2;
ShortBase() { std::cout << "ShortBase display\n"; }
};
class IntBase
{
public:
static constexpr int Mask = 1 << 3;
IntBase() { std::cout << "IntBase display\n"; }
};
// List of all base classes
using AllBases = std::tuple<CharBase, UnsignedCharBase, ShortBase, IntBase>;
constexpr int highestSetBit(const int mask) // This is the only limitation in this design
{
for (int i = 31; i >= 0; --i)
if (mask & (1 << i))
return i;
return -1; // should never reach here for valid masks
}
template<int Mask, typename Tuple, typename Enable = void, typename... Types>
struct TypeExtractor;
template<int Mask, typename Tuple, typename... Types>
struct TypeExtractor<Mask, Tuple, std::enable_if_t<Mask == 0>, Types...>
{
using type = Aggregate<Types...>;
};
template<int Mask, typename Tuple, typename... Types>
struct TypeExtractor<Mask, Tuple, std::enable_if_t<Mask != 0>, Types...>
{
static constexpr int highestBit = highestSetBit(Mask);
using BaseType = std::tuple_element_t<highestBit, Tuple>;
using type = typename TypeExtractor<Mask & ~(1 << highestBit), Tuple, void, Types..., BaseType>::type;
};
template<int Mask>
using ExtractTypes = typename TypeExtractor<Mask, AllBases>::type;
using AggregatePtr = std::unique_ptr<IAggregate>;
template<int Mask>
AggregatePtr createAggregateInstance()
{
return std::make_unique<ExtractTypes<Mask>>();
}
// Helper to create a map of factory functions
template<int... Masks>
constexpr auto createFactoryMap(std::integer_sequence<int, Masks...>)
{
using FuncType = AggregatePtr (*)();
return std::array<FuncType, sizeof...(Masks)> {{&createAggregateInstance<Masks>...}};
}
// The factory map consist of AllBases tuple
constexpr auto factoryMap = createFactoryMap(std::make_integer_sequence<int, 1 << std::tuple_size_v<AllBases>> {});
AggregatePtr createAggregate(int mask)
{
if (mask < factoryMap.size())
return factoryMap[mask]();
return nullptr;
}
int main()
{
for (int i = 1; i <= 3; ++i)
{
auto instance = createAggregate(i);
if (!instance)
std::cout << "Invalid combination for input: " << i << "\n";
std::cout << "\n";
}
return 0;
}