如何提取可变参数函数的一组选定参数并使用它们调用另一个函数 [英] How to extract a selected set of arguments of a variadic function and use them to call another function

查看:85
本文介绍了如何提取可变参数函数的一组选定参数并使用它们调用另一个函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个可变参数函数 zoo ,该函数带有N个参数,其中N在编译时是已知的(它是包含该函数的类的模板参数)。

I have a variadic function zoo which takes N arguments, where N is known at compile time (it is a template parameter of the class containing the function).

template <int N>
struct B
{
    template <typename... Args>
    static void zoo(Args... args)
    {
        static_assert(size of...(args) == N, "");
       // do something
    }
};

我还有另一个可变参数函数 foo ,该函数接受M个参数,其中M> N,并且在编译时已知(它是包含函数的类的模板参数)。我有一个静态index_array,其中包含要传递给 zoo foo 的参数的索引。

I have another variadic function foo which takes M arguments, where M>N and is known at compile time (it is a template parameter of the class containing the function). I have a static index_array containing the indices of the arguments of foo I want to pass to zoo.

foo 的正文中,我想调用 zoo 并传递参数的选定子集foo

From the body of foo I want to call zoo passing a selected subset of the arguments of foo.

执行此操作的最佳方法是什么?理想情况下实现完美的内联,即使所有内容都编译成一条指令而没有任何函数指针间接?

What is the best way to do this? Ideally achieving perfect inlining, i.e. so that everything is compiled into just one instruction with no function pointers indirections?

template<int...I>
struct indices
{
    static constexpr int N = sizeof...(I);
};

template <int M, typename...X>
struct A
{
    // here I am simplifying, in reality IS will be built at compile time based on X
    typedef indices<0,2,3> IS;

    template <typename... Args>
    static void foo(Args... args)
    {
        static_assert(size of...(args) == M, "");
       // do some magic to achieve the function call described in pseudo-code
       // B<IS::N>::zoo(args(IS(0),IS(1),IS(2)))
       // ideally this should be perfectly inlined to just have the call above
    }
};

请注意,上面的代码是我的问题的简化,旨在说明问题。

Please note the code above is a simplification of my problem, designed for the purpose of illustrating the question.

编辑:
如下所述,我描述了用例:
我正在使用基于模板的库来驱动微控制器引脚。微控制器具有多个端口(可作为内存中的字节访问),每个端口最多具有8个引脚(位)。通过模板参数X,A类是一堆针脚,其中每个针脚都定义为Pin。 B类操作同一端口上的所有引脚。 A :: foo是用于修改某些引脚的函数,其参数的顺序与X模板参数包中指定引脚的顺序相同。 foo需要按端口对参数进行分组,然后分派到代表各个端口的B类中,在这些类中,所有参数都在一条指令中融合并写入控制器。

As asked below, I describe the use case: I am playing with a template based library to drive micro-controller pins. A micro controller has several ports (accessible as bytes in memory) and each port has up to 8 pins (bits). Class A is a bundle of pins via the template argument X, where every pin is defined as Pin. Class B manipulates all pins on the same port. A::foo is a function to modify some of the pins, with arguments in the same order as the order with which the pins are specified in the X template argument pack. foo needs to group the arguments by ports and dispatch to the B classes which representing individual ports, where all arguments are fused and written to the controller in a single instruction.

推荐答案

您可以创建一个助手来提取 nth_arg ,如下所示:

You can create a helper to extract the nth_arg like this:

template <int I>
struct ignore
{
  template <typename T>
  ignore(T&&) // This constructor accepts anything
  {
  }
};

template <typename T>
struct nth_arg;

template <size_t... DropIndexes>
struct nth_arg<std::integer_sequence<size_t, DropIndexes...>>
{
  template <typename Arg, typename... Rest>
  static decltype(auto) get(ignore<DropIndexes>..., // ignore args 0...n-1
                            Arg&& arg,
                            Rest&&...) // also ignore the rest
  {
    return std::forward<Arg>(arg); // return nth arg
  }
};

然后致电

template <int... Is, typename... Args>
static void call_zoo(indices<Is...>, Args&&... args)
{
  B<sizeof...(Is)>::zoo(nth_arg<std::make_index_sequence<Is>>::get(
      std::forward<Args>(args)...)...);
}

template <int M>
struct A
{
  typedef indices<0, 2, 3> IS;

  template <typename... Args>
  static void foo(Args... args)
  {
    static_assert(sizeof...(args) == M, "");
    call_zoo(IS{}, std::forward<Args>(args)...);
  }
};

如果您使用的是C ++ 11,则可以轻松滚动自己的 integer_sequence

If you're using C++11, you can easily roll your own integer_sequence.

这篇关于如何提取可变参数函数的一组选定参数并使用它们调用另一个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆