如何将多个 std::function 合并为一个?
How To Combine Multiple std::function To One?
我有多个 std::function
。它们每个都有不同的输入和输出,并且一个 std::function
的输入可能是另一个 std::function
的输出,这意味着 "serial" 从一个转换到另一个。
可能我描述的不够清楚。让代码说话
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
}
这是非常简单的代码,我已经删除了无意义的代码并显示了我的核心意思。
因此您可以看到 convert1
从 double
转换为 int
,convert2
从 int
转换为 char
和 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
函数,这样会更清楚发生了什么。
如果您仍然想使用 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; })
我有多个 std::function
。它们每个都有不同的输入和输出,并且一个 std::function
的输入可能是另一个 std::function
的输出,这意味着 "serial" 从一个转换到另一个。
可能我描述的不够清楚。让代码说话
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
}
这是非常简单的代码,我已经删除了无意义的代码并显示了我的核心意思。
因此您可以看到 convert1
从 double
转换为 int
,convert2
从 int
转换为 char
和 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
函数,这样会更清楚发生了什么。
如果您仍然想使用 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; })