简体   繁体   English

可变参数模板作为第一个 arguments

[英]Variadic template as first arguments

I want to write a generic template function that accepts and calls a number of different functions and performs additional setup and teardown operations.我想编写一个通用模板 function 接受和调用许多不同的函数并执行额外的设置和拆卸操作。 The functions signatures differ in the first arguments, such as:第一个 arguments 中的函数签名不同,例如:

void foo(int i, void* self, (*callback)(void*, int i));
void bar(bool s, bool r, void* self, (*callback)(void*, int i));

I also want to pick out the self argument and the callback , but letting the arguments in front of them vary.我也想挑出self参数和callback ,但是让它们前面的 arguments 有所不同。 I understand this must be hard to do with variadric templates due to how the unpacking works;我知道由于解包的工作原理,这对于可变参数模板一定很难做到; is there any way around it?有什么办法吗?

If I understand your question correctly, your issue is to use variadic templates in any order as an argument, except as the first one.如果我正确理解您的问题,您的问题是以任何顺序使用可变参数模板作为参数,除了第一个。 Well, thankfully all these are valid:好吧,谢天谢地,所有这些都是有效的:

template<class T, class ...Args> void call1(int y, T first, Args ... args, int x);
template<class T, class ...Args> void call2(int y, int x, T first, Args ... args);
template<class T, class ...Args> void call3(Args ... args, T first, int y, int x);
Edit:
Automatic template deduction will only work for call2
Thanks to @Human-Compiler

Of course, variadic templates are dealt with using recursion, so, in order to handle them correctly, you'll also need a function to call should there be no first argument provided:当然,可变参数模板使用递归处理,因此,为了正确处理它们,如果没有提供first参数,您还需要一个 function 来调用:

void call1(int y, int x);

An example, which will just blindly call the first x functions:一个例子,它只会盲目地调用第一个 x 函数:

void print()
{
  std::cout << "print";
}
void call(int x)
{
  return;
}
template<class T, class ...Args> void call(int x, T f, Args ... args)
{
  if(x <= 0) return;
  f();
  call(--x, args...);
}

int main()
{
  call(3, print, print, print);
}

Depending on your use-case, you can either accept callback and self as first arguments, before a parameter pack, and then merge those two in proper order:根据您的用例,您可以在参数包之前接受callbackself作为第一个 arguments,然后以正确的顺序合并这两个:

#include <tuple>
#include <functional>

template <typename F, typename... Ts>
void wrap(F f, void* self, void (*callback)(void*, int), Ts&&... ts)
{
    // change self and callback
    std::apply(f, std::tuple_cat(std::forward_as_tuple(std::forward<Ts>(ts)...),
                                 std::make_tuple(self, callback)));
}

DEMO演示

Or extract arguments based on their position in the parameter pack:或者根据参数包中的position提取arguments:

#include <tuple>
#include <functional>

template <typename F, typename... Ts>
void wrap(F f, Ts&&... ts)
{
    constexpr int N = sizeof...(Ts);
    auto args = std::tie(ts...);

    void*& self = std::get<N-2>(args);
    void (*&callback)(void*, int) = std::get<N-1>(args);

    // change self and callback
    std::apply(f, args);
}

With retaining value categories the above becomes:使用保留值类别,上述内容变为:

#include <tuple>
#include <cstddef>
#include <utility>

template <typename Tuple, std::size_t... Is>
auto take(Tuple&& t, std::index_sequence<Is...>)
{
    return std::forward_as_tuple(std::get<Is>(std::forward<Tuple>(t))...);
}

template <typename F, typename... Ts>
void wrap(F f, Ts&&... ts)
{
    constexpr int N = sizeof...(Ts);
    auto args = std::tie(ts...);

    void* self = std::get<N-2>(args);
    void (*callback)(void*, int) = std::get<N-1>(args);

    auto firsts = take(std::forward_as_tuple(std::forward<Ts>(ts)...),
                       std::make_index_sequence<N-2>{});

    // change self and callback    
    std::apply(f, std::tuple_cat(std::move(firsts), std::make_tuple(self, callback)));
}

DEMO 2演示 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM