使用 C++ 中的字符串从类名创建对象 [英] Create object from class name using a string in C++

查看:111
本文介绍了使用 C++ 中的字符串从类名创建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Base 类:

class Base() {
public:
   Base(int, int);
   ~Base();
};

我有多个继承自 Base 的类:

I have multiple classes that inherit from Base:

class childA : public Base {
public:
  childA(int, int, string);
  ~childA();
};

childA::childA(int x, int y, string str) : Base (x, y)
{
// do something here
}

childBchildC 等也一样

我想知道是否可以使用字符串创建 childAchildBchildC.我听说过可变参数模板,但我真的不明白如何使用它.

I want to know if it's possible to create childA, childB or childC using a string. I heard about variadic tempaltes but I don't really understand how to use it.

推荐答案

Variadic 模板是一个模板,它可以接受任意数量的任何类型的模板参数.自 C 语言诞生以来,这两个函数都可以是可变参数的(例如 printf 函数),然后是宏,现在是模板.

Variadic template is a template, which can take an arbitrary number of template arguments of any type. Both the functions could be variadic since dawn of C language (printf function, for example), then macros and now - templates.

你可以这样声明:

template<typename... Arguments> class Variadic;

然后用任意数量的参数专门化它,包括零:

then specialize it with any number of arguments, including zero:

Variadic<double> instance;
Variadic<double, std::string> instance;
Variadic<> instance;

然后您可以使用参数列表,称为参数包,如下所示:

Then you may use the argument list, known as argument pack, like this:

template<typename... Arguments> void SampleFunction(Arguments... parameters);

就像可变参数函数一样,参数包可以在具体参数之前:

Just as in case of variadic functions, the argument pack can be preceded by concrete arguments:

template<typename First, typename... Rest> class BunchOfValues;

STL 中有一个经典的可变参数模板示例:std::tuple.一些编译器不完全支持或根本不支持此功能,在他们的情况下,元组是通过元编程和宏定义实现的.在 C++ 中没有直接的方法从列表中选择特定的参数,就像可变参数函数一样.可以使用递归在一个方向上迭代它们:

There is classic example of variadic template in STL: std::tuple. Some compilers do not support this feature fully or do not support at all, and in their case tuple is implemented through metaprogramming and macro definitions. There is no direct way in C++ to select particular argument from the list, like it is possible with variadic functions. It's possible to use recursion to iterate through them in one direction:

template<typename T> foo(T first)
{
    // do something;
}

template<typename T, typename U, typename ... Args> foo(T first, U second, Args... Rest)
{
    // do something with T
    foo(second, Rest...); 
}

通常迭代将依赖于函数重载,或者 - 如果函数一次只能选择一个参数 - 使用愚蠢的扩展标记:

Usually iteration would rely on function overloading, or - if the function can simply pick one argument at a time - using a dumb expansion marker:

template<typename... Args> inline void pass(Args&&...) {}

可以如下使用:

  template<typename... Args> inline void expand(Args&&... args) {
    pass( some_function(args)... );
  }

  expand(42, "answer", true);

将扩展为:

 pass( some_function(arg1), some_function(arg2), some_function(arg3) etc... );

这个pass"函数的使用是必要的,因为参数包的扩展是通过用逗号分隔函数调用参数来进行的,这与逗号运算符不等价.some_function(args)...; 永远不会工作.此外,上述解决方案仅在 some_function 的返回类型不为 void 时才有效.此外, some_function 调用将以未指定的顺序执行,因为函数参数的评估顺序未定义.为了避免未指定的顺序,可以使用大括号括起来的初始化列表,这保证了严格的从左到右的评估顺序.为避免需要 not void 返回类型,可以使用逗号运算符在每个扩展元素中始终产生 1.

The use of this "pass" function is necessary, since the expansion of the argument pack proceeds by separating the function call arguments by commas, which are not equivalent to the comma operator. some_function(args)...; will never work. Moreover, this above solution will only work when the return type of some_function is not void. Furthermore, the some_function calls will be executed in an unspecified order, because the order of evaluation of function arguments is undefined. To avoid the unspecified order, brace-enclosed initializer lists can be used, which guarantee strict left-to-right order of evaluation. To avoid the need for a not void return type, the comma operator can be used to always yield 1 in each expansion element.

  struct pass {
    template<typename ...T> pass(T...) {}
  };

  pass{(some_function(args), 1)...};

参数包中参数的个数可以由sizeof...(args)表达式决定.

The number of arguments in argument pack can be determined by sizeof...(args) expression.

在创建使用调用 name 的初始化器时,只有在编写代码时定义了 name 才有可能.可以使用预处理器中的 Stingizer 运算符 #,例如

As of creating initializers that use calls name it is possible only if name is defined at time of writing the code. There stingizer operator # in preprocessor that can be used, e.g.

#define printstring( x ) printf(#x "\n")

printstring( This a dumb idea );

将生成代码(假设 C++ 自动连接字符串文字):

will generate code (assuming that C++ automatically joins string literals):

printf("This a dumb idea \n")

你可以这样声明:

template<typename T> class moniker
{
public:
    moniker(const char* tname);
}

#define declare_moniker(type, name)  moniker<type> name(#type)

可变参数宏定义和可变参数模板如何交互?我不确定.我手头的编译器失败了,但它不是 C++11.有兴趣的话试试看.

How would variadic macro definitions and variadic template interact? I'm not sure. Compiler I have at hand failed, but it isn't C++11. Try that, if interested.

可能支持 typeid 运算符,具体取决于编译器设置.

There might be typeid operator supporeted, depending on compiler settings.

const std::type_info&ti1 = typeid(A);

const std::type_info& ti1 = typeid(A);

std::type_info 得到了方法 name(),但它返回的字符串取决于实现:http://en.cppreference.com/w/cpp/types/type_info/name

std::type_info got method name(), but string it returns is implementation dependant: http://en.cppreference.com/w/cpp/types/type_info/name

这篇关于使用 C++ 中的字符串从类名创建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆