[英]How to instantiate a list of types for compile-time/static polymorphism
I'm implementing a compile time dispatcher which makes use of static polymorphism and metaprogramming.我正在实现一个使用 static 多态性和元编程的编译时调度程序。
I have a list of types which I would like to instantiate into a runtime std::array
.我有一个类型列表,我想将其实例化为运行时
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();
}
In the above code, mp_list
is simply a variadic template which 'expands' to struct<A, B, C> mp_list
.在上面的代码中,
mp_list
只是一个“扩展”为struct<A, B, C> mp_list
的可变参数模板。 And likewise, mp_size
gives an mp implementation of the sizeof
.同样,
mp_size
给出了sizeof
的 mp 实现。
As can be inferred, the Thing_list
is an array with a compile-time known size.可以推断,
Thing_list
是一个具有编译时已知大小的数组。
I can then specialize a template function like so:然后我可以像这样专门化一个模板 function :
template<> int process<Test::B>(int foo, float bar){ /* do stuff */ };
to achieve compile-time polymorphism.实现编译时多态性。
The above code works well, except that to initialize it, I am stuck at doing this in the constructor:上面的代码运行良好,除了初始化它,我坚持在构造函数中这样做:
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
}
There are two things I'm unable to get right:有两件事我无法做对:
list
definition in the declaration, I would like my initialization to automatically reflect that list type.list
定义时,我希望我的初始化能够自动反映该列表类型。integral_constant
but the use of const char*
as a template parameter seems to be forbidden.integral_constant
的东西,但似乎禁止使用const char*
作为模板参数。 I am left to having to duplicate declaration (triplicate, really). This answer is almost the solution: it takes a list of types and instantiates them like so:这个答案几乎是解决方案:它需要一个类型列表并像这样实例化它们:
static std::tuple<int*, float*, foo*, bar*> CreateList() {
return { Create<int>(), Create<float>(), Create<foo>(), Create<bar>() };
}
However, I'm stuck on converting from std::tuple
to std::array
.但是,我坚持从
std::tuple
转换为std::array
。
The main question is #1.主要问题是#1。 Bonus for #2 without using
#define
based trickery.不使用基于
#define
的诡计的 #2 奖励。
If anyone cares: this code is destined for embedded software.如果有人在乎:这段代码是为嵌入式软件设计的。 There are dozens of different types, and importantly, each type (eg
A
, B
, C
) will have an identically structured configuration to be loaded from memory (eg under a configuration key for "A"
) - hence the reason of wanting to have access to the string name of the type at runtime.有几十种不同的类型,重要的是,每种类型(例如
A
, B
, C
)都将具有从 memory 加载的相同结构的配置(例如,在"A"
的配置键下) - 因此想要拥有在运行时访问类型的字符串名称。
Not sure to understand what do you exactly want but...不知道你到底想要什么,但......
Given that you can use at least C++17 (for auto
template parameters), you can define outside your class some variables as鉴于您至少可以使用 C++17 (用于
auto
模板参数),您可以在 class 之外定义一些变量为
static constexpr char nops[] = "NOP";
static constexpr char A[] = "A";
static constexpr char B[] = "B";
static constexpr char C[] = "C";
Then a simple wrapper that accept nops
, A
, B
, etc. as template parameters然后是一个简单的包装器,它接受
nops
、 A
、 B
等作为模板参数
template <auto val>
struct wrap
{ };
Then a using
that, given a variadic list of template value parameters, create a mp_list
of wrap
types然后
using
它,给定模板值参数的可变参数列表,创建wrap
类型的mp_list
template <auto ... vals>
using wrapper = mp_list<wrap<vals>...>;
At this point... I suppose that, inside Test
, you can define nop
and list
as follows此时......我想,在里面
Test
,你可以定义nop
和list
如下
using nop = wrap<nops>;
using list = wrapper<A, B, C>;
Using delegating constructor, meta-programming way to initialize your thing_list
could be the following使用委托构造函数,初始化你的
thing_list
的元编程方式可能如下
template <auto ... vals>
Test (mp_list<wrap<vals>...>)
: thing_list{{{&Test::process<wrap<vals>>, vals}...}}
{ }
Test () : Test{list{}}
{ }
If you modify the list
adding a D
parameter (where D
is the "D"
literal)如果您修改
list
添加D
参数(其中D
是"D"
字面量)
using list = wrapper<A, B, C, D>;
automagically the you get an additional {&Test::process<wrap<D>>, D}
element in your thing_list
.你会自动在你的
thing_list
中获得一个额外的{&Test::process<wrap<D>>, D}
元素。
The following is a full compiling C++17 example下面是一个完整的编译C++17的例子
#include <array>
#include <string>
#include <type_traits>
template <typename...>
struct mp_list
{ };
template <typename>
struct mp_size;
template <typename ... Ts>
struct mp_size<mp_list<Ts...>>
: public std::integral_constant<std::size_t, sizeof...(Ts)>
{ };
static constexpr char nops[] = "NOP";
static constexpr char A[] = "A";
static constexpr char B[] = "B";
static constexpr char C[] = "C";
template <auto val>
struct wrap
{ };
template <auto ... vals>
using wrapper = mp_list<wrap<vals>...>;
struct Test
{
using nop = wrap<nops>;
using list = wrapper<A, B, C>;
struct Things
{
int (Test::*process)(int foo, float bar);
const std::string key;
// int something;
// float other;
};
using Thing_list = std::array<Things, mp_size<list>::value>;
Thing_list thing_list;
template<typename T=nop> int process(int foo, float bar)
{ return 0; }
template <auto ... vals>
Test (mp_list<wrap<vals>...>)
: thing_list{{{&Test::process<wrap<vals>>, vals}...}}
{ }
Test () : Test{list{}}
{ }
};
int main ()
{
Test t;
}
I would suggest changing the typedef
s for A, B and C to struct so you can define the string inside them.我建议将 A、B 和 C 的
typedef
更改为 struct,以便您可以在其中定义字符串。
struct A {
static constexpr int value = 1;
static constexpr char name[] = "A";
};
// Same for B and C
using list = mp_list<A, B, C>;
Then you can create a make_thing_list
然后你可以创建一个
make_thing_list
template <typename... T>
static std::array<Things, sizeof...(T)> make_thing_list(mp_list<T...>) {
return {{{&Test::process<T>, T::name}...}};
}
auto thing_list = make_thing_list(list{});
Complete example完整示例
#include <string>
#include <array>
#include <iostream>
template <typename... T>
struct mp_list {};
struct Test
{
struct nop {
static constexpr int value = 0;
static constexpr char name[] = "nop";
};
struct A {
static constexpr int value = 1;
static constexpr char name[] = "A";
};
struct B {
static constexpr int value = 2;
static constexpr char name[] = "B";
};
struct C {
static constexpr int value = 3;
static constexpr char name[] = "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;
};
template <typename... T>
static std::array<Things, sizeof...(T)> make_thing_list(mp_list<T...>) {
return {{{&Test::process<T>, T::name}...}};
}
using Thing_list = decltype(make_thing_list(list{}));
Thing_list thing_list = make_thing_list(list{});
template<typename T=nop> int process(int foo, float bar) {
return T::value;
}
// stuff...
Test() {}
};
int main() {
Test t;
static_assert(std::is_same_v<decltype(t.thing_list), std::array<Test::Things, 3>>);
for (auto& thing : t.thing_list) {
std::cout << thing.key << (t.*thing.process)(1, 1.0) << '\n';
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.