【发布时间】:2021-03-28 11:07:26
【问题描述】:
我正在实现一个使用静态多态性和元编程的编译时调度程序。
我有一个类型列表,我想将其实例化到运行时 std::array。
struct Test
{
typedef std::integral_constant<int,0> nop;
typedef std::integral_constant<int,1> A;
typedef std::integral_constant<int,2> B;
typedef std::integral_constant<int,3> C;
using list = mp_list<A, B, C>; // mp_list expands to: template<A, B, C> struct {};
struct Things{
int (Test::*process)(int foo, float bar);
const std::string key;
int something;
float other;
};
typedef std::array<Things, mp_size<list>::value> Thing_list;
Thing_list thing_list;
template<typename T=nop> int process(int foo, float bar);
// stuff...
Test();
}
在上面的代码中,mp_list 只是一个“扩展”为struct<A, B, C> mp_list 的可变参数模板。同样,mp_size 给出了sizeof 的 mp 实现。
可以推断,Thing_list 是一个具有编译时已知大小的数组。
然后我可以像这样专门化一个模板函数:
template<> int process<Test::B>(int foo, float bar){ /* do stuff */ };
实现编译时多态性。
上面的代码运行良好,除了初始化它,我坚持在构造函数中这样做:
Test::Test() thing_list({{{&Test::process<A>, "A"}, // this all should be achieved through meta-programming
{&Test::process<B>, "B"},
{&Test::process<C>, "C"}}}} )
{
// stuff
}
有两件事我无法做到:
- 我想要一个基于 MP 的列表初始化。当我更新声明中的
list定义时,我希望我的初始化能够自动反映该列表类型。 - 我还想避免将类型名称复制为字符串文字。我曾尝试使用
integral_constant之类的东西,但似乎禁止使用const char*作为模板参数。我不得不重复声明(真的是一式三份)。
This 答案几乎是解决方案:它需要一个类型列表并像这样实例化它们:
static std::tuple<int*, float*, foo*, bar*> CreateList() {
return { Create<int>(), Create<float>(), Create<foo>(), Create<bar>() };
}
但是,我坚持从 std::tuple 转换为 std::array。
主要问题是#1。不使用基于 #define 的诡计的 #2 奖励。
如果有人关心的话:这段代码是为嵌入式软件设计的。有几十种不同的类型,重要的是,每种类型(例如A、B、C)都将具有从内存中加载的相同结构的配置(例如,在"A" 的配置键下) - 因此想要在运行时访问类型的字符串名称的原因。
【问题讨论】:
-
除非您在某处明确指定,否则您永远无法将变量/类型的名称作为字符串获取。
-
对于提出的一般问题的方法,我会做类似
auto thing_list = make_thing_list<list>();。 -
CreateList如我提供的链接中所示,确实是make_thing_list<list>(),但是,它会创建一个std::tuple。对于我的生活,我不能将元组变成数组。
标签: c++ embedded metaprogramming template-meta-programming