在C ++ 03中使用std :: bind2nd的复合函数

时间:2015-05-05 07:16:55

标签: c++ bind c++03

我想让一些函数/函子充当复合函数/函子:

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

或者,让我们在我的真实例子中这样做: 我有一个函数double g(T1 u, T2 v)来计算一些东西。我想循环遍历向量u中的所有vector<T1> vecInput,并使用固定的第二个参数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会失败......

2 个答案:

答案 0 :(得分:1)

  

我有函数f(x, y)g(u, v),我想创建一个函数指针或仿函数h(t) = f(g(t,C1), C2)。我必须在C ++ 03中完成。

仅使用C ++ 03标准库中提供的适配器无法编写函数。显然,没有什么能阻止你自己实现这个功能。但是,如果你想利用任何现有的库,并获得真正的单行,那么几乎没有其他选择:

选项#1:SGI扩展

libstdc ++附带the standard library extensions from SGI。它提供了几个额外的适配器和仿函数,即:compose1compose2constant1。它们可以通过以下方式组合:

#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扩展名

std::bind扩展库中也可以找到C ++ 11 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);
  

f(x,y)函数实际上是一个成员函数vector::push_back

在C ++ 03中绑定成员函数时,通常会使用std::mem_funstd::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算法替换为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

答案 1 :(得分:0)

重要的是要记住,这些库函数并不神奇,它们只是推断出相关的类型。

在您的情况下,您不需要所有这些灵活性,只是因为您知道自己需要vector::push_back。而不是推导一个相当复杂的类型,只需显式创建一个类型来捕获函数。甚至有一种类型的库类型,std::back_insert_iterator,但一般情况下你可以自己做。

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