使用C 中的字符串从类名称创建对象

Create object from class name using a string in C++

本文关键字:创建对象 字符串 使用      更新时间:2023-10-16

我有一个Base类:

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

我有多个从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。我听说过variadic tempaltes,但我真的不明白如何使用它。

variadic模板是一个模板,可以采用任何类型的任意数量的模板参数。自C语言的黎明(例如,printf函数),然后是宏和现在 - 模板。

以来,这两个函数都可以是变性

您可以这样声明:

template<typename... Arguments> class Variadic;

然后使用任意数量的参数进行专业化,包括零:

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

然后您可以使用称为参数包的参数列表,例如:

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

就像在variadic函数的情况下一样,参数包可以在具体参数之前:

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

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

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...); 
}

通常迭代将依靠函数过载,或者 - 如果函数一次可以一次选择一个参数,则使用愚蠢的扩展标记:

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

可以使用如下:

  template<typename... Args> inline void expand(Args&&... args) {
    pass( some_function(args)... );
  }
  expand(42, "answerswer", true);

将扩展到以下内容:

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

使用此"通过"功能是必要的,因为参数包的扩展是通过将函数调用参数分开的逗号来进行的,逗号不等于逗号运算符。some_function(args)...;永远不会起作用。而且,只有在some_function的返回类型没有无效的情况下,以上解决方案才能起作用。此外,某些函数调用将以未指定的顺序执行,因为函数参数的评估顺序是未定义的。为了避免未指定的订单,可以使用支撑封闭的初始化器列表,以确保严格的左右评估顺序。为了避免需要非空隙返回类型,逗号运算符可以始终在每个扩展元素中产生1个。

  struct pass {
    template<typename ...T> pass(T...) {}
  };
  pass{(some_function(args), 1)...};

参数包中的参数数可以通过sizeof...(args)表达式确定。

创建使用调用名称的初始化器时,只有在编写代码时定义名称时才有可能。可以使用的预处理器中的刺刺操作员#,例如

#define printstring( x ) printf(#x "n")
printstring( This a dumb idea );

将生成代码(假设C 自动加入字符串文字):

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)

variadic宏定义和variadic模板如何相互作用?我不知道。我手头的编译器失败了,但不是C 11。如果有兴趣,请尝试。

根据编译器设置,可能会有typeid操作员的支持。

const std :: type_info&amp;ti1 = typeid(a);

std :: type_info获取方法名称(),但是字符串返回的字符串取决于:http://en.cppreference.com/w/cpp/types/type/type_info/name

在C 14中您可以创建一些辅助结构来确定您在编译时传递的每个字符串的字符字符,并将其转发到类型。但是,您通过的字符串需要存储在linkage的变量中,以使编译器将其用作非类型模板参数:

#include <utility>
#include <type_traits>
template <char... Cs>
struct string_literal { };
template <class T, T &, class>
struct make_string_literal_impl;
template <class T, T &Cs, std::size_t... Is>
struct make_string_literal_impl<T, Cs, std::index_sequence<Is...>> {
    using type = string_literal<Cs[Is]...>;
};
template <class T, T &>
struct make_string_literal;
template <class T, std::size_t N, T (&Cs)[N]>
struct make_string_literal<T[N], Cs>: make_string_literal_impl<T[N], Cs, std::make_index_sequence<N>> {
};
struct Base {
   Base(int, int) { }
   ~Base() { }
};
template <class>
struct Child: Base { 
    using Base::Base;
};
constexpr char const str[] = "abc";
int main() {
    Child<make_string_literal<decltype(str), str>::type> c(1, 1);
}

[live demo]