C++中的函数组合

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.


Rob*_*son 5

偶然发现这个问题,我想向今天遇到这个问题的任何人指出,由于 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)


Edw*_*nge 3

我不知道有什么支持您目前想要的语法。然而,创建一个是一件简单的事情。只需重写函子的 *(例如 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)

未经测试,但我怀疑如果它不能开箱即用,它已经很接近了。