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

时间:2016-12-16 16:14:20

标签: c++ templates object inheritance

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

2 个答案:

答案 0 :(得分:0)

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

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

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

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

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, "answer", true);

将扩展为:

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

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

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

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

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

在创建使用调用名称的初始化程序时,只有在编写代码时定义了name才有可能。可以使用预处理器中的stingizer operator#,例如

#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)

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

根据编译器设置,可能会支持typeid运算符。

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

std :: type_info得到方法名称(),但它返回的字符串是依赖于实现的:http://en.cppreference.com/w/cpp/types/type_info/name

答案 1 :(得分:0)

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

#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]