变量模板作为第一个参数

问题描述 投票:1回答:1

我想写一个通用的模板函数,它接受并调用一些不同的函数,并执行额外的设置和拆卸操作。这些函数签名的不同之处在于第一个参数,如。

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

我还想挑选出 self 争论和 callback但让它们前面的参数变化。我知道由于解包的工作方式,这在变量模板中一定很难做到,有什么办法可以解决吗?

c++ metaprogramming
1个回答
1
投票

根据你的使用情况,你可以接受 callbackself 作为第一个参数,放在参数包之前,然后将这两个参数按照适当的顺序合并。

#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

或者根据参数包中的位置提取参数。

#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);
}

在保留值类别的情况下,上面的参数就变成了。

#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


1
投票

如果我对你的问题理解正确的话,你的问题是,除了作为第一个参数外,以任何顺序使用可变模板作为参数。好吧,幸好这些都是有效的。

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

当然,可变模板是用递归来处理的 所以,为了正确地处理它们 你还需要一个函数来调用,如果没有的话 first 提供的参数。

void call1(int y, int x);

一个例子,它只是盲目地调用第一个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);
}
© www.soinside.com 2019 - 2024. All rights reserved.