我正在尝试提出一种更好的方法来表示以下内容:

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/

10-11 23:24
查看更多