如何将多个std ::函数结合到一个

How To Combine Multiple std::function To One?

本文关键字:一个 结合 函数 std      更新时间:2023-10-16

我有多个std::function。他们每个人都有不同的输入和输出,一个std::function的输入可能是另一个std::function的输出,这意味着"串行"从一个转换为另一个。

也许我不能足够清楚地描述它。让代码谈话

std::function<bool(double)> combine(std::function<int(double)> convert1
                                    , std::function<char(int)> convert2
                                    , std::function<bool(char)> convert3)
{
    return std::bind(convert1, convert2, convert3)//error. A function directly convert [double] to [bool] using convert1, convert2, convert3
}

这是非常简单的代码,我已经删除了毫无意义的代码并显示了我的含义的核心。

因此,您可以看到convert1double转换为intconvert2int转换为CC_8,而convert3进行从char转换为bool。现在,我需要将它们组合在一起,以便可以将double直接转换为bool

您知道,我真的不想将double转换为bool。它只是进行测试。

实现此目的的一个选项是编写帮助函数:

bool helper(double d
            , std::function<int(double)> convert1
            , std::function<char(int)> convert2
            , std::function<bool(char)> convert3)
{
    return convert3(convert2(convert1(d)));
}
std::function<double(bool)> combine(std::function<int(double)> convert1
                                    , std::function<char(int)> convert2
                                    , std::function<bool(char)> convert3)
{
    return helper;
}

但这是丑陋的代码,也许我以一种共同的方式使用此转换,这意味着我应该为我的各种转换编写此helper

那么,是否有一种直接的方法将这些功能组合在一起?

您可以使用lambda表达式执行此操作。


std::function<bool(double)> combine(std::function<int(double)> convert1
                                    , std::function<char(int)> convert2
                                    , std::function<bool(char)> convert3)
{
    return [=](double d){return convert3(convert2(convert1(d)));}
}

或者您可以直接在代码中使用lambda,并且根本不使用此combine功能,也更清楚地发生了什么。


如果您仍然想使用组合功能并想要一个更通用的功能,也许您可以尝试这样的东西。(只是一个简单的例子)

template<typename Converter>
auto combineX(Converter converter){
   return converter;
}
template<typename Converter, typename ...Converters>
auto combineX(Converter converter, Converters... converters){
   return [converter,remain = combineX(converters...)](auto x){return remain(converter(x));};
}

创建一个简单的类型特征来提取最后一个函数的输入类型

template <typename, typename...>
struct lastFnType;
template <typename F0, typename F1, typename ... Fn>
struct lastFnType<F0, F1, Fn...>
 { using type = typename lastFnType<F1, Fn...>::type; };
template <typename T1, typename T2>
struct lastFnType<std::function<T2(T1)>>
 { using type = T1; };

您可以在更通用的变异模板递归解决方案

中转换Apple Apple的解决方案( 1)
template <typename T1, typename T2>
std::function<T1(T2)> combine (std::function<T1(T2)> conv)
 { return conv; }
template <typename T1, typename T2, typename T3, typename ... Fn>
std::function<T1(typename lastFnType<std::function<T2(T3)>, Fn...>::type)>
    combine (std::function<T1(T2)> conv1, std::function<T2(T3)> conv2, 
             Fn ... fn)
 {
   using In = typename lastFnType<std::function<T2(T3)>, Fn...>::type;
   return [=](In const & in){ return conv1(combine(conv2, fn...)(in)); };
 }

,但观察到转换器的顺序是倒的(首先用最后使用的转换器致电;因此combine(convert3, convert2, convert1)

以下是一个完整的示例

#include <functional>
template <typename, typename...>
struct lastFnType;
template <typename F0, typename F1, typename ... Fn>
struct lastFnType<F0, F1, Fn...>
 { using type = typename lastFnType<F1, Fn...>::type; };
template <typename T1, typename T2>
struct lastFnType<std::function<T2(T1)>>
 { using type = T1; };
template <typename T1, typename T2>
std::function<T1(T2)> combine (std::function<T1(T2)> conv)
 { return conv; }
template <typename T1, typename T2, typename T3, typename ... Fn>
std::function<T1(typename lastFnType<std::function<T2(T3)>, Fn...>::type)>
    combine (std::function<T1(T2)> conv1, std::function<T2(T3)> conv2, 
             Fn ... fn)
 {
   using In = typename lastFnType<std::function<T2(T3)>, Fn...>::type;
   return [=](In const & in){ return conv1(combine(conv2, fn...)(in)); };
 }
int fn1 (double d)
 { return d*2.0; }
char fn2 (int i)
 { return i+3; }
bool fn3 (char c)
 { return c == 'a'; }

int main ()
 {
   std::function<int(double)> f1 { fn1 };
   std::function<char(int)> f2 { fn2 };
   std::function<bool(char)> f3 { fn3 };
   auto cmb = combine(f3, f2, f1);
   bool b { cmb(3.2) };
 }

您可以做:

template <typename T, typename F>
decltype(auto) apply(T&& t, F&& f)
{
    return std::forward<F>(f)(std::forward<T>(t));
}
template <typename T, typename F, typename... Fs>
decltype(auto) apply(T&& t, F&& f, Fs&&... fs)
{
    return apply(std::forward<F>(f)(std::forward<T>(t)), std::forward<Fs>(fs)...);
}

使用:

apply(4,
      [](int i) { return i * 10; },
      [](auto i) {return i + 2;},
      [](auto n){ return n / 10.f; })

demo