boost函数和lambda包装函数

时间:2011-10-06 13:30:15

标签: c++ boost boost-function boost-lambda

我想转换这个简单的代码:

void setZComp(Imath::V3f& pt)
{
    pt.z = 0.0;
}

int myfunc()
{
    ...

    std::vector<Imath::V3f> vec(5,Imath::V3f(1.0,1.0,1.0));
    std::for_each(vec.begin(),vec.end(),boost::bind(&setZComp,_1));

    ...
}

之类的东西,为了不在外面声明setZComp,而是某种内联声明

int myfunc()
{
    ...

    boost::function<double(Imath::V3f&)> f = (boost::lambda::_1 ->* &Imath::V3f::z = 0.0) ;
    std::for_each(vec.begin(),vec.end(),boost::bind(&f,_1));

    ...
}

我对Boost Bind和Lambda很新,我不知道这是否可以通过某种方式完成。显然上面的代码不起作用。

6 个答案:

答案 0 :(得分:2)

你是否正在使用大锤打破坚果?有时,我认为使用普通的for循环并自己明确设置变量更简单。这使代码更容易阅读和维护。

typedef std::vector<Imath::V3f> V3fVector;
V3fVector vec(5,Imath::V3f(1.0,1.0,1.0));

for (V3fVector::iterator i = vec.begin(), iEnd = vec.end(); iEnd != i; ++i)
    i->z = 0.0;

尽管boost绑定很有用,但它也是一种语法混乱,使得简单的代码无法读取。

答案 1 :(得分:2)

如果你不能使用C ++ 11 lambda,那么你可以使用boost::lambda::bind 所以在你的情况下,如下所示:

boost::lambda::bind(&Imath::V3f::z, boost::lambda::_1) = 0.0

一个完整的例子,因为我不知道你的内部:

struct S
{
    S():i(0){};
    int i;
};
int main()
{
    std::vector<S> vec;
    vec.push_back(S());

    std::for_each(vec.begin(), vec.end(), boost::lambda::bind(&S::i, boost::lambda::_1) = 5);
    std::cout << vec.front().i << std::endl; // outputs 5
    return 0
}

答案 2 :(得分:1)

你也可以考虑看一下boost :: phoenix。我认为这是一个比lambda库更完整的c ++函数式编程实现。

答案 3 :(得分:1)

Member variables as targets部分所述:

  

指向成员变量的指针实际上不是函数,但[boost::lambda::bind]函数的第一个参数仍然是指向成员变量的指针。调用这样的绑定表达式将返回对数据成员的引用。

因此,要构建一个访问z成员的lambda表达式,您可以使用:

boost::lambda::bind(&Imath::V3f::z, boost::lambda::_1)

返回的对象本身可以在其他表达式中使用。例如,

boost::lambda::bind(&Imath::V3f::z, boost::lambda::_1) = 0.0

表示“获取double引用第一个参数的z成员(类型Imath::V3f&)并赋值0.0”。

然后,您可以将此lambda与Boost.Function和std::for_each

一起使用
boost::function<void(Imath::V3f&)> f = boost::lambda::bind(&Imath::V3f::z, boost::lambda::_1) = 0.0;
std::for_each(vec.begin(), vec.end(), f);

作为参考,这是一个完整的,可编译的例子:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <boost/function.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>

namespace Imath
{
class V3f
{
public:
    double x, y, z;

    V3f(double x_, double y_, double z_)
        : x(x_), y(y_), z(z_)
    {
    }

    friend std::ostream& operator<<(std::ostream& os, const V3f& pt) {
        return (os << '(' << pt.x << ", " << pt.y << ", " << pt.z << ')');
    }
};
}

int main()
{
    std::vector<Imath::V3f> vec(5, Imath::V3f(1.0, 1.0, 1.0));
    boost::function<void(Imath::V3f&)> f = boost::lambda::bind(&Imath::V3f::z, boost::lambda::_1) = 0.0;
    std::for_each(vec.begin(), vec.end(), f);

    std::vector<Imath::V3f>::iterator it, end = vec.end();
    for (it = vec.begin(); it != end; ++it) {
        std::cout << *it << std::endl;
    }

    return EXIT_SUCCESS;
}

输出:

(1, 1, 0)
(1, 1, 0)
(1, 1, 0)
(1, 1, 0)
(1, 1, 0)

答案 4 :(得分:0)

如果您可以访问具有C ++ 11支持的最新版g++或MSVC 2010,则可以执行以下操作:

int myfunc()
{
    ...

    std::for_each(vec.begin(),vec.end(),[](Imath::V3f& pt){ pt.z = 0.0; });

    ...
}

答案 5 :(得分:0)

如果你想使用boost :: lambda,我有时会发现在包含lambda的行之前声明一个“指向成员的指针”变量更清晰,然后允许你使用 - &gt; *运算符而不是使用boost :: lambda :: bind。

然而,正如艾伦所指出的,这里的简单循环可能是最简单的解决方案。使用BOOST_FOREACH使其更简单。

这是mkaes示例实现的修改版本,它使用operator - &gt; *而不是bind,它还显示了如何使用BOOST_FOREACH作为替代。

#include <iostream>
#include <vector>
#include <boost/lambda/lambda.hpp>
#include <boost/foreach.hpp>

// I like to provide alternate names for the boost::lambda placeholders
boost::lambda::placeholder1_type& arg1 = boost::lambda::_1 ;
boost::lambda::placeholder2_type& arg2 = boost::lambda::_2 ;
boost::lambda::placeholder3_type& arg3 = boost::lambda::_3 ;

struct S
{
    S():i(0){};
    int i;
};

int main()
{
    std::vector<S> vec;
    vec.push_back(S());

    // Define this pointer-to-member so we can
    //  use it in the lambda via the ->* operator
    int S::* i = &S::i ;

    std::for_each(vec.begin(), vec.end(), &arg1->*i = 5);
    std::cout << vec.front().i << std::endl; // outputs 5

    // Alternatively, just use a simple foreach loop
    BOOST_FOREACH( S & s, vec )
    {
        s.i = 6 ;
    }
    std::cout << vec.front().i << std::endl; // outputs 6

    return 0 ;
}