简体   繁体   English

如何分区参数包?

[英]How to partition a parameter pack?

I'd like to write a function template, apply , which receives some function f , an integer i , and a parameter pack. 我想写一个函数模板, apply ,它接收一些函数f ,一个整数i和一个参数包。 apply needs to unpack the parameters and apply f to them, except for the i th parameter, pi . apply需要解压缩参数并对它们应用f ,第i个参数pi除外。 For pi , it needs to call some other function g before passing it as a parameter to f . 对于pi ,它需要在将其作为参数传递给f之前调用其他函数g

It seems that I need a way to partition the parameter pack into a left side, the i th parameter, and the right side. 似乎我需要一种方法将参数包分区为左侧,第i个参数和右侧。 Is this possible? 这可能吗? In code: 在代码中:

template<int i, typename Function, typename... Parms>
  void apply(Function f, Parms... parms)
{
  auto lhs = // what goes here?
  auto pi =  // what goes here?
  auto rhs = // what goes here?

  f(lhs..., g(pi), rhs...);
}

OK, here we go! 好的,我们走吧! It really ugly but I couldn't come up with a nicer version in a hurry ;) Most of the stuff is bog standard template specialization. 真的很丑,但我不能匆忙提出一个更好的版本;)大多数东西是沼泽标准模板专业化。 The biggest issue is creating a list of integers of the proper size. 最大的问题是创建一个适当大小的整数列表。 I seem to recall that I came up with a nice version but somehow I can't recall what I did. 我似乎记得我提出了一个不错的版本,但不知怎的,我不记得我做了什么。 Enjoy! 请享用!

#include <iostream>
#include <utility>

// printing the values
void print_args() {}
template <typename F> void print_args(F f) { std::cout << f; }
template <typename F, typename... T>
void print_args(F f, T... args)
{
    std::cout << f << ", ";
    print_args(args...);
}

// the function object to be called:
struct Functor
{
    template <typename... T>
    void operator()(T... args)
    {
        std::cout << "f(";
        print_args(args...);
        std::cout << ")\n";
    }
};

// conditionally apply g():
template <typename T> T g(T value) { return 1000 + value; }
template <int i, int j, typename T>
typename std::enable_if<i != j, T>::type forward(T t) { return t; }
template <int i, int j, typename T>
typename std::enable_if<i == j, T>::type forward(T t) { return g(t); }

// create a series of integers:
template <int... Values> struct values {};

template <int Add, typename> struct combine_values;
template <int Add, int... Values>
struct combine_values<Add, values<Values...>>
{
    typedef values<Values..., Add> type;
};

template <int Size> struct make_values;
template <> struct make_values<0> { typedef values<> type; };
template <int Size>
struct make_values
{
    typedef typename combine_values<Size, typename make_values<Size -1>::type>::type type;
};

// applying f(t...) except for ti where g(ti) is called
template <int i, int... Values, typename Function, typename... T>
void apply_aux(values<Values...>, Function f, T... t)
{
    f(forward<i, Values>(t)...);
}

template <int i, typename Function, typename... T>
void apply(Function f, T... t)
{
    apply_aux<i>(typename make_values<sizeof...(T)>::type(), f, t...);
}

int main()
{
    apply<3>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8);
    apply<4>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8);
    apply<5>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8);
}

Iactually did code something similar a little while ago. 不久之前我实际上编写了类似的代码。 So try the following code: 因此,请尝试以下代码:

template<unsigned N, unsigned M>
struct call_up_impl{
    template<class Func, class Mutator, class Tuple, class... Args>
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) {
        call_up_impl<N-1, M>::do_call(func, mutator, args, std::get<N-1>(args), std::forward<Args>(unpacked_args)...);
    }
};

template<unsigned M>
struct call_up_impl<0, M> {
    template<class Func, class Mutator, class Tuple, class... Args>
    static void do_call(const Func& func, const Mutator&, const Tuple&, Args&&... unpacked_args) {
        func(std::forward<Args>(unpacked_args)...);
    }
};
template<unsigned M>
struct call_up_impl<M, M> {
    template<class Func, class Mutator, class Tuple, class... Args>
    static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) {
        call_up_impl<M-1, M>::do_call(func, mutator, args, mutator(std::get<M-1>(args)), std::forward<Args>(unpacked_args)...);
    }
};
template<int i, typename Function, typename... Parms>
void apply(Function f, Parms... parms) {
      std::tuple<Parms...> t(parms...);
      call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t);
}

This is a quick adaption of my original code, so it isn't thoroughly tested and maybe not the not optimal way to do this, but it should work at least (at least according to a quick test and depending what exactly you want). 这是我原始代码的快速修改,所以它没有经过彻底的测试,也许不是最好的方法,但它应该至少起作用(至少根据快速测试并根据你想要的确切)。 It should be possible to do this without the tuple, but I haven't gotten that to compile with g++ (it doesn't seem to like the nested variadic templates needed). 应该可以在没有元组的情况下执行此操作,但我没有用g ++编译(它似乎不喜欢所需的嵌套可变参数模板)。 However changing apply to: 但是更改apply于:

template<int i, typename Function, typename... Parms>
void apply(Function f, Parms&&... parms) {
      std::tuple<Parms&&...> t(std::forward<Parms>(parms)...);
      call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t);
}

will probably avoid most of the overhead introduced by the tuple. 可能会避免元组引入的大部分开销。 It would be even better to make correct forwarding of the results of the std::get calls, but I'm too tired to work that out write now. 如果正确转发std::get调用的结果会更好,但是我现在太累了,不能写出来。

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

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