为每个算法传递多个函数

Passing multiple functions to for each algorithm

我想问一下是否可以为每个算法(如在 STL 中)定义将多个函数作为输入参数并按从左到右的顺序对其进行评估的算法?

template <typename Iterator, typename ... Args>
void for_each(Iterator begin, Iterator end, Args ... args) {
// apply functions passed in Args... to range [begin,end)
}

我如何访问 Args 传递的那些函数?是否只有一些模板递归才有可能?

你不必为此做一些特殊的模板技巧,只需像下面这样定义一个递归:

template <typename Iterator, typename F>
void recurse(Iterator first, Iterator last, F f) {
  if(first != last) {
    f(*(first++));
  }   
}

template <typename Iterator, typename F, typename ...Args>
void recurse(Iterator first, Iterator last, F f, Args ...args) {
  if(first != last) {
    f(*(first++));
    recurse(first, last, args...);
  }   
}

template <typename Iterator, typename ...Args>
void variadic_for_each(Iterator first, Iterator last, Args ...args) {
  recurse(first, last, args...); 
}

LIVE DEMO

你可以这样使用:

#include <iostream>
#include <utility>
#include <algorithm>

template <typename Iterator, typename F1>
void for_each(Iterator begin, Iterator end, F1 f1)
{
   std::for_each(begin, end, f1);
}

template <typename Iterator, typename F1, typename... Fun>
void for_each(Iterator begin, Iterator end, F1 f1, Fun... fs)
{
   std::for_each(begin, end, f1);
   for_each(begin, end, fs...);
}

int main()
{
    std::array<int, 5> a =  {1,2,3,4,5};

    auto f1 = [](int i){std::cout << "f1: " << i << " ";};
    auto f2 = [](int i){std::cout << "f2: " << i << " ";};

    for_each(a.begin(), a.end(), f1, f2);
}

输出:

f1: 1 f1: 2 f1: 3 f1: 4 f1: 5 f2: 1 f2: 2 f2: 3 f2: 4 f2: 5 

live example

我写了一些更通用的东西——一些伪代码展示了它能做什么:

auto funcs = mk<TupleOfFunctions>(f, g, h); // f, g, h -- callables
// mk is my helper function, I defined it in # Usage # section
funcs(arg) == h(g(f(arg))); // similiar to pipe in shell
                            // echo arg | f | g | h

说白了就是class的模板。它是构造函数,可以接受任意数量的可调用对象。调用它的实例将 return 构造函数接收到的每个函数转换的参数。
而且,因为它是可调用的,所以您应该能够将它传递给 for_each.

代码

#include <utility>
// 1 //
template <typename T, typename U>
struct PairOfFunctions: std::pair<T, U> {
    using std::pair<T, U>::pair;

    template <typename... Args>
    auto operator() (Args&&... args) {
        return std::pair<T, U>::second(std::pair<T, U>::first(args...));
    }
};


template<typename...>
struct TupleOfFunctions;
// 2 //
template<typename T, typename... U>
struct TupleOfFunctions<T, U...>: PairOfFunctions<T, TupleOfFunctions<U...> >{
    using PairOfFunctions<T, TupleOfFunctions<U...> >::PairOfFunctions;
    TupleOfFunctions(T t, U... u):
        PairOfFunctions<T, TupleOfFunctions<U...> >(
            t,
            TupleOfFunctions<U...>(u...)
        )
        {}
};
// 3 //
template<>
struct TupleOfFunctions<>{
    template <typename T>
    T operator() (T t) { // probably not optimal, too lazy to overload
        return t;
    }
};

一些解释

  1. PairOfFunctions – subclass of pair:

    mk<PairOfFunctions>(f, g)(arg) == g(f(arg));
    
  2. TupleOfFunctionsPairOfFunctions 的泛化,需要一个或多个可调用项。

  3. TupleOfFunctions<>:特殊情况——没有函数,returns 参数副本。

用法

我的例子很笨,请随意替换它。

// My universal helper
template<template <typename...> class T, typename... Args>
auto mk(Args... args){
    return T<Args...>{args...};
}

int main()
{
    auto a = mk<TupleOfFunctions>(
        [](int a) {return a*2;},
        [](int a) {return a + 10;},
        [](int a) {return a / 2;}
    );
    std::cout << a(4) << '\n'; // (4 * 2 + 10) / 2
}

See it working online