【问题标题】:boost function and lambda to wrap a functionboost 函数和 lambda 来包装一个函数
【发布时间】:2011-10-06 13:30:14
【问题描述】:

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

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 还是很陌生,我不知道这是否可以通过某种方式完成。显然上面的代码不起作用。

【问题讨论】:

  • 让我放弃使用 boost::lambda 的原因之一是很难像您尝试做的那样访问成员。
  • 您应该知道,随着最近发布的Boost.Phoenix,Boost.Lambda 现已正式弃用。使用 Phoenix 代替新代码。 :-]

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


【解决方案1】:

你在用大锤打碎坚果吗?有时,我认为只使用普通的 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 绑定很有用,但它也是一个语法混乱,使简单的代码不可读。

【讨论】:

    【解决方案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
    }
    

    【讨论】:

      【解决方案3】:

      您也可以考虑看看 boost::phoenix。我认为它比 lambda 库更全面地实现了 C++ 函数式编程。

      【讨论】:

        【解决方案4】:

        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&amp;)并赋值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)

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

            如果你想使用 boost::lambda,我有时会发现在包含 lambda 的行之前立即声明一个“指向成员的指针”变量会更简洁,这样你就可以使用 ->* 运算符来代替使用 boost::lambda::bind。

            但是,正如 Alan 指出的那样,这里的简单循环可能是最简单的解决方案。使用 BOOST_FOREACH 让它更简单。

            这是 mkaes 示例实现的修改版本,它使用 operator ->* 而不是 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 ;
            }
            

            【讨论】:

              猜你喜欢
              • 2011-06-23
              • 2021-04-06
              • 2013-05-23
              • 1970-01-01
              • 2012-03-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-12-05
              相关资源
              最近更新 更多