我正在尝试提出一种更好的方法来表示以下内容:
using InsBase0 = std::tuple<std::string, std::function<void()>>;
static const std::array<InsBase0, 1> ins0_bases = {{
{"NOP", 0x0},
}};
using InsBase1 = std::tuple<std::string, std::function<void(const std::string &)>>;
static const std::array<InsBase1, 7> ins1_bases = {{
{"INC", 0x0},
{"DEC", 0x0},
{"AND", 0x0},
{"OR", 0x0},
{"XOR", 0x0},
{"CP", 0x0},
{"SUB", 0x0},
}};
using InsBase2 = std::tuple<std::string, std::function<void(const std::string &, const std::string&)>>;
static const std::array<InsBase2, 6> ins_bases = {{
{"LD", 0x0},
{"ADD", 0x0},
{"ADC", 0x0},
{"SBC", 0x0},
{"JP", 0x0},
{"JR", 0x0},
}};
(完全人为的示例,想象一下用函数代替
0x0
和更合理的东西,例如映射而不是数组或结构而不是元组)上下文是这是一个汇编程序,因此我需要将指令映射到函数。
在理想的情况下,我希望能够将所有指令放入一个数组/容器中(使用一个额外的
args
成员来表示该函数需要的args数量),但是我很乐意不复制以及StructName0
的定义 最佳答案
元编程助手的两位:
template<std::size_t I>
using index=std::integral_constant<std::size_t, I>;
template<class T> struct tag_t {constexpr tag_t(){};};
template<class T> tag_t<T> tag{};
template<std::size_t, class T>
using indexed_type = T;
现在,我们为每个参数计数定义一个枚举类型:
enum class zero_op:std::size_t { NOP };
enum class one_op:std::size_t { INC };
enum class two_op:std::size_t { ADD };
接下来,从类型到参数计数的映射:
constexpr index<0> args( tag_t<zero_op> ) { return {}; }
constexpr index<1> args( tag_t<one_op> ) { return {}; }
constexpr index<2> args( tag_t<two_op> ) { return {}; }
这需要一个模板以及一个计数和一个类型,然后将类型重复传递给模板:
template<template<class...>class Z, class T, class Indexes>
struct repeat;
template<template<class...>class Z, class T, std::size_t I>
struct repeat<Z, T, index<I>>:
repeat<Z, T, std::make_index_sequence<I>>
{};
template<template<class...>class Z, class T, std::size_t...Is>
struct repeat<Z, T, std::index_sequence<Is...>> {
using type=Z<indexed_type<Is, T>...>;
};
template<template<class...>class Z, class T, std::size_t N>
using repeat_t = typename repeat<Z, T, index<N>>::type;
我们使用它来构建我们的
std::function
签名:template<class...Args>
using void_call = std::function<void(Args...)>;
template<std::size_t N, class T>
using nary_operation = repeat_t< void_call, T, N >;
nary_operation< 3, std::string const& >
是std::function<void(std::string const&,std::string const&,std::string const&)>
。我们使用它来创建一个编译时多态表:
template<class...Es>
struct table {
template<class E>
using operation = nary_operation<args(tag<E>), std::string const&>;
template<class E>
using subtable = std::map< E, operation<E> >;
std::tuple< subtable<Es>... > tables;
template<class E>
operation<E> const& operator[]( E e ) {
return std::get< subtable<E> >( tables )[e];
}
};
或类似的东西。
如果您具有
table<zero_op, one_op, two_op> bob
的实例,则可以执行bob[ zero_op::NOP ]();
要么
bob[ zero_op::INC ]("foo");
要么
bob[ zero_op::ADD ]("foo", "bar");
[]
中的枚举类型更改返回的函数对象的类型。上面可能有错别字。
但是,最终结果是类型安全的。
关于c++ - 具有可变参数数目的函数成员的容器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40468475/