为每个算法传递多个函数

时间:2015-10-30 19:32:06

标签: c++ templates variadic-templates

我想问一下,是否有可能为每个算法(如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传递的那些功能?是否只能使用一些模板递归?

3 个答案:

答案 0 :(得分:2)

您可以使用以下内容:

#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

答案 1 :(得分:1)

你不必为此做一些特殊的模板技巧,只需定义一个递归,如下所示:

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

答案 2 :(得分:1)

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

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

用简单的英语,它是班级的模板。它的构造函数可以获取任何数量的callables。调用它的实例将返回由构造函数接收的每个函数转换的参数 并且,因为它可以调用,所以你应该能够将它传递给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 - 对的子类:

    mk<PairOfFunctions>(f, g)(arg) == g(f(arg));
    
  2. TupleOfFunctions - PairOfFunctions的推广,需要一个或多个callables。

  3. TupleOfFunctions<>:特殊情况 - 不接受任何函数,返回参数副本。

  4. 用法

    我的例子是愚蠢的,随意更换它。

    // 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