Cha*_*l72 9 c++ boost functional-programming
有许多令人印象深刻的Boost库,如Boost.Lambda或Boost.Phoenix,它们使C++成为一种真正的功能语言.但有没有一种直接的方法可以从任何2个或更多任意函数或函子创建复合函数?
如果我有:int f(int x)并且int g(int x),我想做一些像f . g静态生成一个新的函数对象的东西f(g(x)).
这似乎可以通过各种技术实现,例如这里讨论的技术.当然,您可以链接调用boost::lambda::bind以创建复合仿函数.但是Boost中是否有任何东西可以轻松地让你接受任何2个或更多的函数或函数对象并将它们组合起来创建一个复合函子,类似于你在Haskell这样的语言中的表达方式?
小智 10
对于任何绊到这个页面的人来说,有一个关于这个主题的博客文章来自第14局:
http://blog.quasardb.net/function-composition-in-c11/
这利用了C++ 11中的新功能以及使用boost.
偶然发现这个问题,我想向今天遇到这个问题的任何人指出,由于 decltype、auto 和完美转发,这可以通过使用标准库和一些帮助类的相对优雅的语法实现。
定义这两个类:
template <class Arg, class ArgCall, class OuterCall>
class pipe {
private:
ArgCall argcall;
OuterCall outercall;
public:
typedef pipe<Arg, ArgCall, OuterCall> this_type;
pipe(ArgCall ac, OuterCall oc) : argcall(ac), outercall(oc) {}
auto operator()(Arg arg) -> decltype(outercall(argcall(arg))) {
return outercall(argcall(arg));
}
template <class NewCall>
pipe<Arg, this_type, NewCall> operator[](NewCall&& nc) {
return {*this, std::forward<NewCall>(nc)};
}
};
template <class Arg>
class pipe_source {
public:
typedef pipe_source<Arg> this_type;
Arg operator()(Arg arg) {
return arg;
}
template <class ArgCall, class OuterCall>
static pipe<Arg, ArgCall, OuterCall> create(ArgCall&& ac, OuterCall&& oc) {
return {std::forward<ArgCall>(ac), std::forward<OuterCall>(oc)};
}
template <class OuterCall>
pipe<Arg, this_type, OuterCall> operator[](OuterCall&& oc) {
return {*this, std::forward<OuterCall>(oc)};
}
};
Run Code Online (Sandbox Code Playgroud)
一个简单的程序:
int f(int x) {
return x*x;
}
int g(int x) {
return x-2;
}
int h(int x) {
return x/2;
}
int main() {
auto foo = pipe_source<int>::create(f, g);
//or:
auto bar = pipe_source<int>()[g][h];
std::cout << foo(10) << std::endl;
std::cout << bar(10) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这有一个额外的好处,即一旦它在管道中,只要返回类型正确,您就可以使用 pipe[f] 将另一个函数 f 添加到链中。
然后:
$ g++ test.cpp -o test -std=c++11
$ ./test
98
4
$
Run Code Online (Sandbox Code Playgroud)
我不知道有什么支持您目前想要的语法。然而,创建一个是一件简单的事情。只需重写函子的 *(例如 boost::function<>),即可返回复合函子。
template < typename R1, typename R2, typename T1, typename T2 >
boost::function<R1(T2)> operator * (boost::function<R1(T2)> const& f, boost::function<R2(T2)> const& g)
{
return boost::bind(f, boost::bind(g, _1));
}
Run Code Online (Sandbox Code Playgroud)
未经测试,但我怀疑如果它不能开箱即用,它已经很接近了。