Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 允许传递不同构造函数参数的对象注册表_C++_Templates_Polymorphism_C++17_C++20 - Fatal编程技术网

C++ 允许传递不同构造函数参数的对象注册表

C++ 允许传递不同构造函数参数的对象注册表,c++,templates,polymorphism,c++17,c++20,C++,Templates,Polymorphism,C++17,C++20,注意:如果你喜欢,请建议一个更好的标题,我没能想出一个更好的 考虑简单的C++对象注册表,按名称创建代码< >类对象< /代码>和后代的实例。 我有一些,但简而言之,我所做的是: class Foo : public Object { /* ... */ }; Registrar<Foo> _foo("MyFoo"); // Register class Foo with name "MyFoo" // ... auto foo = Regi

注意:如果你喜欢,请建议一个更好的标题,我没能想出一个更好的

考虑简单的C++对象注册表,按名称创建代码< >类对象< /代码>和后代的实例。 我有一些,但简而言之,我所做的是:

class Foo : public Object { /* ... */ };

Registrar<Foo> _foo("MyFoo"); // Register class Foo with name "MyFoo"
// ...
auto foo = Registry::createObject("MyFoo"); // Returns a new Foo object
我必须意识到的每一个想法到目前为止都没有被编译,不知何故,我在这里陷入了一个棘手的困境

简而言之,我的尝试集中在将对象创建代码(
make_unique
)从辅助对象lambda移动到
createObject
,并使其成为可变模板,如。但它不起作用,因为我无法在模板类型之间转换。一些尝试也失败了


我不知道如何克服这个问题,我怀疑类似的东西可能会有所帮助,但我不确定如何编写它。

您正在尝试执行运行时多态性,但函数参数是编译时构造。因此,您需要将编译时构造转换为运行时构造。一种简单的方法是使用类型擦除,可能通过
std::any

您注册的类型应该有一个
显式
构造函数,该构造函数接受
std::any
。这允许
Registry::createObject
any
作为参数。然后它将把这个
any
传递给所讨论类型的构造函数

这就是通讯协议。构造函数的调用方需要将要传递的参数打包为
std::tuple
(或接收对象知道的任何其他单个对象:

auto bar = Registry::createObject("MyBar", 42);
...
auto baz = Registry::createObject("I_take_three_arguments", 42, 3.14, "Hello world");
您的
createObject
函数将以获取任意
tuple
为模板,并将其捆绑到
any
中以发送给构造函数:

template<typename ...Args>
Object *Registry::createObject(char const*, Args ...&&args)
{
  using tpl = std::tuple<std::remove_cvref_t<Args>...>
  std::any params(std::in_place_type_t<tpl>(), std::forward<Args>(args));
  //pass `params` to the registry function.
}
如果你想变得更聪明,你的
注册器
系统可以得到感兴趣的类构造函数的参数类型列表,它可以使用元编程技术来制造代码来解包
任何存储的
元组
本身


请注意,此机制只允许您为一组特定的参数使用一个特定的构造函数,绝对没有隐式转换或重载。

如果每个类型都有不同的构造函数参数,只需直接构造它们,就不需要任何公共注册表对象。如果您有一组类型具有
(int)
构造函数和另一组具有
(int、double、string)的类型
constructors,创建两个独立的注册表。调用
Registry::createObject
时,不需要根据字符串参数来决定调用哪种构造函数。@n.“代词m:示例用例:假设我从文本文件中读取了要创建的对象+参数,例如XML:我可以像
之类的条目。这看起来像是一个现实的场景,不是吗?在这种情况下,我需要创建不同的注册表吗?那么您如何准确地从
到达
注册表::createObject(“MyBar”,42);
?您能显示代码吗?@n.“代词m。没有代码,因为这是我试图实现的:-)。在
Foo
案例中,这很简单。在
Bar
的情况下,我需要找到一种将参数传递给构造函数的方法,这在目前是不可能的。我想到了类似于
std::invoke
,在这里我可以传递带有任意参数的任意函数。我的误解在哪里?当然没有代码。这是有原因的。一个XML文件中可以有无限多组类型的参数,但程序中对
Registry::createObject
的调用实例却很少。您希望在程序中有多少个对
Registry::createObject
的调用实例?我怀疑一个好的答案应该是“一”。你喜欢不同的答案吗?
template<typename ...Args>
Object *Registry::createObject(char const*, Args ...&&args)
{
  using tpl = std::tuple<std::remove_cvref_t<Args>...>
  std::any params(std::in_place_type_t<tpl>(), std::forward<Args>(args));
  //pass `params` to the registry function.
}
Bar(std::any params)
{
  auto [first] = std::any_cast<std::tuple<int>>(params);
  //use `first`.
}

...
I_take_three_arguments(std::any params)
{
  auto [i, f, str] = std::any_cast<std::tuple<int, float, const char*>>(params);

  //Use these.
}