C++03 中带 std::bind2nd 的复合函数

Composite function with std::bind2nd in C++03

我想得到一些 function/functor 作为复合 function/functor:

具体来说,我有函数f(x, y)g(u, v),我想创建一个函数指针或仿函数h(t) = f(g(t,C1), C2),这样我就可以传递仿函数h进入 for_each() 循环,其中 C1、C2 是一些常数。

或者,让我们在我的真实示例中这样做: 我有一个函数 double g(T1 u, T2 v) 可以计算一些东西。我想从向量 vector<T1> vecInput 循环遍历所有 u,并使用固定的第二个参数 t2VConst。计算完所有这些数字后,我想将它们保存到一个向量中 vector<double> results.

我想用类似这样的东西来做:

foreach(vecInput.begin(), vecInput.end(), std::bind2nd(&results::push_back, std::bind2nd(g, t2VConst)))

请注意,在这种情况下,f(x,y) 函数实际上是一个成员函数 vector::push_back。 (好像push_back只有一个参数,但是作为成员函数,它多了一个参数,就是对象本身。)

更糟的是,我真的必须用 C++03 来做,而不是 C++11。有什么解决办法吗?此外,我希望解决方案可以更简洁(如果可以像上面那样在一行中完成的话)。

更新

bind2nd() 的相关问题: 我得到了编译错误,现在我将它简化为更简单的代码来查看它:

#include <functional>
#include <algorithm>

#define CASE2   // choose define of CASE1 to CASE3

#ifdef CASE1
double g(double x, double y)   // 1. OK
#endif
#ifdef CASE2
double g(double &x, double y)  // 2. overload error
#endif
#ifdef CASE3
double g(double *x, double y)  // 3. OK
#endif
{
#ifdef CASE2
    x  = 5.0;
#endif
#ifdef CASE3
    *x = 5.0;
#endif
    // Note: no case1, since in case 1, x is a local variable, 
    // no meaning to assign value to it.

    return 3.0;
}

int main(int argc, char *argv[])
{
    double t = 2.0;
    double u;

#if defined(CASE1) || defined(CASE2)
    u = std::bind2nd(std::ptr_fun(&g), 3.0)(t);
#endif
#ifdef CASE3
    u = std::bind2nd(std::ptr_fun(&g), 3.0)(&t);
#endif
}

我不知道为什么 CASE 2 失败了...

重要的是要记住,这些库函数并不神奇,它们只是推导相当复杂的类型。

在您的情况下,您不需要所有这些灵活性,只是因为您知道自己需要 vector::push_back。与其推导一个相当复杂的类型,不如显式创建一个类型来捕获函数。甚至还有一种库类型可以执行此操作,std::back_insert_iterator,但通常您可以自己完成。

因此,您最终会得到一个模板 class,它采用类型名称 T1 和 T2,存储 &gT2 C2std::vector<double>&。它只是实现 void operator()(T1 t1) { v.pus_back(g(t1, C2)); }.

I have functions f(x, y), and g(u, v), and I want to create a function pointer or functor h(t) = f(g(t,C1), C2). I have to do it in C++03.

不可能仅使用 C++03 标准库中可用的适配器来组合函数。显然,没有什么能阻止您自己实现此功能。但是,如果您想利用任何现有的库,并获得真正的单行代码,则几乎没有其他选择:

选项 #1:SGI 扩展

libstdc++ 随 the standard library extensions from SGI. It provides several additional adapters and functors, namely: compose1, compose2 and constant1 一起提供。它们可以通过以下方式组合:

#include <functional>
#include <ext/functional>

int f(int x, int y);
int g(int u, int v);
const int arg = 1;
const int C1 = 2;
const int C2 = 3;

__gnu_cxx::compose2(std::ptr_fun(&f)
                  , std::bind2nd(std::ptr_fun(&g), C1)
                  , __gnu_cxx::constant1<int>(C2)
                 )(arg);

选项 #2:TR1 扩展

C++11 的 std::bind 的初始实现也可以在 tr1 扩展库中找到:

#include <tr1/functional>

int f(int x, int y);
int g(int u, int v);
const int arg = 1;
const int C1 = 2;
const int C2 = 3;

std::tr1::bind(&f
             , std::tr1::bind(&g
                            , std::tr1::placeholders::_1
                            , C1)
             , C2
            )(arg);

选项 #3:Boost 库

Boost.Bind 库可能是最便携的解决方案:

#include <boost/bind.hpp>

int f(int x, int y);
int g(int u, int v);
const int arg = 1;
const int C1 = 2;
const int C2 = 3;

boost::bind(&f, boost::bind(&g, _1, C1), C2)(arg);

The f(x,y) function is really a member function vector::push_back

在 C++03 中绑定成员函数时,您通常会使用 std::mem_fun together with std::bind1st 来绑定对象参数:

Class object;
std::bind1st(std::mem_fun(&Class::func), &object)(arg);

但是,对于通过引用获取其参数的成员函数,这将失败。再一次,您可以使用 Boost/TR1 代替:

boost::bind(&std::vector<double>::push_back
          , &results
          , boost::bind(&g, _1, C1)
          )(arg);

请注意,当切换到 C++11 时,您需要手动解析重载 std::vector<double>::push_back

但幸运的是,您的用例有资格被 std::transform algorithm with std::back_inserter 替换,它将负责调用向量的 push_back 成员函数以获取转换后的参数。

#include <algorithm>
#include <functional>
#include <iterator>

int g(int u, int v);
const int C1 = 2;
std::vector<int> input, output;

std::transform(input.begin(), input.end()
             , std::back_inserter(output)
             , std::bind2nd(std::ptr_fun(&g), C1));

DEMO