我正在实现一个使用静态多态和元编程的编译时调度程序。
我有一个类型列表,我想将这些类型实例化到运行时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
}有两件事我做不好:
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的诡计的第二种奖励。
如果有人关心的话:这段代码注定要用于嵌入式软件。有几十种不同的类型,重要的是,每种类型(例如A、B、C)都将有一个结构相同的配置从内存中加载(例如,在"A"的配置键下)--因此需要在运行时访问该类型的字符串名称。
发布于 2021-03-28 14:58:57
我建议将A、B和C的typedefs更改为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>;然后您可以创建一个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{});完整示例
#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';
}
}发布于 2021-03-28 13:00:02
不知道你到底想要什么但是..。
考虑到至少可以使用C++17 (对于auto模板参数),您可以将类外部的一些变量定义为
static constexpr char nops[] = "NOP";
static constexpr char A[] = "A";
static constexpr char B[] = "B";
static constexpr char C[] = "C";然后是一个接受nops、A、B等模板参数的简单包装器。
template <auto val>
struct wrap
{ };然后,给出一个模板值参数的可变列表的using,创建一个wrap类型的mp_list。
template <auto ... vals>
using wrapper = mp_list<wrap<vals>...>;现在..。我想,在Test中,您可以定义nop和list,如下所示
using nop = wrap<nops>;
using list = wrapper<A, B, C>;使用委托构造函数来初始化thing_list的元编程方法可以如下所示
template <auto ... vals>
Test (mp_list<wrap<vals>...>)
: thing_list{{{&Test::process<wrap<vals>>, vals}...}}
{ }
Test () : Test{list{}}
{ }如果修改list,添加一个D参数(其中D是"D"文本)
using list = wrapper<A, B, C, D>;自动地,您将在您的{&Test::process<wrap<D>>, D}中获得一个额外的thing_list元素。
下面是一个完整的编译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;
}https://stackoverflow.com/questions/66840757
复制相似问题