我想构造一个在运行时根据
enum class
值选择的类型的对象。类 A
和 B
有多个构造函数,这些构造函数具有不同数量的参数,可以在运行时使用。我尝试编写一个工厂方法,将 shared_ptr
返回到基类来尝试解决此问题。
这是我的错误尝试:
enum class Type
{
A,
B // C, etc
};
struct Base{};
struct A : public Base
{
A(const int a) { std::cout << "A::A(int)"; }
A(double d) { std::cout << "A::A(double)"; }
A(int a, double d) { std::cout << "A::A(int,double)"; }
};
struct B : public Base
{
B(int i, double d) { std::cout << "B::B(double)"; }
B(int a, double d, double dd) { std::cout << "B::B(int,double, double)"; }
};
template <typename... Args>
std::shared_ptr<Base> make_Type(Type t, Args &&...args)
{
if (t == Type::A)
return std::make_shared<A>(std::forward<Args>(args)...);
else if (t == Type::B)
return std::make_shared<B>(std::forward<Args>(args)...);
else
assert(false);
}
毫无疑问,这是行不通的。我可以使用
if constexpr
创建静态版本。但如何尝试运行时版本呢? (可能不使用typeinfo
)。
也欢迎任何替代方法。
您可能正在寻找这样的东西:
template <typename T, typename... Args>
std::enable_if_t<std::is_constructible_v<T, Args&&...>, std::shared_ptr<T>>
safe_make_shared(Args&&... args) {
return std::make_shared<T>(std::forward<Args>(args)...);
}
template <typename T>
std::shared_ptr<T> safe_make_shared(...) { return nullptr; }
template <typename... Args>
std::shared_ptr<Base> make_Type(Type t, Args &&...args)
{
switch (t) {
case Type::A : return safe_make_shared<A>(std::forward<Args>(args)...);
case Type::B : return safe_make_shared<B>(std::forward<Args>(args)...);
default: assert(false); return nullptr;
}
}
这个想法是有一个
safe_make_shared
函数,如果类型实际上可以使用给定的参数集构造,则创建对象,否则返回 null (或者它可以断言,或抛出异常作为后备)。重要的是 safe_make_shared
可以使用任何参数集进行实例化,但仅尝试将“正确”的参数集传递给对象的构造函数。