c++ - 展开不同长度的参数包

标签 c++ c++11 c++14 variadic-templates

我想“生成”一个函数指针跳转表。指向的函数以两种类型模板化。应该为两个类型列表中的每个可能对实例化一个不同的函数。理想情况下,我们可以有类似的东西:

#include <tuple>

template <typename X, typename Y>
void foo()
{}

template <typename... Xs, typename... Ys>
void bar(const std::tuple<Xs...>&, const std::tuple<Ys...>&)
{
  using fun_ptr_type = void (*) (void);
  static constexpr fun_ptr_type jump_table[sizeof...(Xs) * sizeof...(Ys)]
    = {&foo<Xs, Ys>...};
}

int main ()
{
  using tuple0 = std::tuple<int, char, double>;
  using tuple1 = std::tuple<float, unsigned long>;

  bar(tuple0{}, tuple1{});
}

正如预期的那样,当元组具有不同的长度时它会失败:

foo.cc:15:20: error: pack expansion contains parameter packs 'Xs' and 'Ys' that have different lengths (3 vs. 2)
    = {&foo<Xs, Ys>...};
            ~~  ~~ ^
foo.cc:23:3: note: in instantiation of function template specialization 'bar<int, char, double, float, unsigned long>' requested here
  bar(tuple0{}, tuple1{});
  ^
1 error generated.

为了实现这种功能,我已经尝试并成功地使用了 indirection (第一个跳转表包含指向另一个跳转表的函数的指针),但我觉得它很笨拙。

那么,我的问题是:是否有解决方法?

最佳答案

您的示例代码是错误的,即使它可以编译(即当 sizeof...(Xs) == sizeof...(Ys) 时)。 比如说,你有 N 元元组,然后 jump_table 有 N*N 个元素,但只有前 N 个元素用函数 ptrs 初始化。

首先,您需要内部连接 ​​2 个类型列表:

template<class A, class B>
struct P;

template<class... Ts>
struct L {};

template<class T, class... Ts>
using mul = L<P<T, Ts>...>;

template<class...>
struct cat;

template<class T>
struct cat<T>
{
    using type = T;
};

template<class... As, class... Bs>
struct cat<L<As...>, L<Bs...>>
{
    using type = L<As..., Bs...>;
};

template<class A, class B, class... Ts>
struct cat<A, B, Ts...>
{
    using type = typename cat<typename cat<A, B>::type, Ts...>::type;
};

template<class A, class B>
struct join;

template<class... As, class... Bs>
struct join<L<As...>, L<Bs...>>
{
    using type = typename cat<mul<As, Bs...>...>::type;
};

例如,

join<L<int[1], int[2]>, L<float[1], float[2], float[3]>>::type

给你

L<P<int[1], float[1]>, P<int[1], float[2]>, P<int[1], float[3]>, P<int[2], float[1]>, P<int[2], float[2]>, P<int[2], float[3]>

回到你的例子:

template <typename X, typename Y>
void foo()
{}

template<class T, std::size_t N>
struct jump_table
{
    template<class... As, class... Bs>
    constexpr jump_table(L<P<As, Bs>...>)
      : table{&foo<As, Bs>...}
    {}

    T table[N];
};

template <typename... Xs, typename... Ys>
void bar(const std::tuple<Xs...>&, const std::tuple<Ys...>&)
{
  using fun_ptr_type = void (*) (void);
  static constexpr jump_table<fun_ptr_type, sizeof...(Xs) * sizeof...(Ys)> table
    = {typename join<L<Xs...>, L<Ys...>>::type()};
}

int main ()
{
  using tuple0 = std::tuple<int, char, double>;
  using tuple1 = std::tuple<float, unsigned long>;

  bar(tuple0{}, tuple1{});
}

这应该符合您的预期。

关于c++ - 展开不同长度的参数包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25656992/

相关文章:

c++ - 可以在 Windows 中使用 clang-cl 标志 -fprofile-instr-generate -fcoverage-mapping

c++ - C++中的数组分配在具有不同长度的堆栈上

c++ - std::function 赋值应该忽略返回类型吗?

c++ - 这两个片段有什么区别?

c++ - 阻止 X3 符号匹配子字符串

c++ - 调用 xSemaphoreGive 后,xSemaphoreTake 不会恢复任务

c++ - C++11 中是否有实际的 4 位整数数据类型

C++ 通过引用传递和通过值函数传递副作用?

c++ - 模拟虚方法的构造函数行为

c++ - 父级上 protected 构造函数和继承的默认构造函数不 protected