代码之家  ›  专栏  ›  技术社区  ›  rlbond

为什么bind1st和bind2nd需要常量函数对象?

  •  1
  • rlbond  · 技术社区  · 14 年前

    所以,我写了一个C++程序,它可以让我控制整个世界。我已经写完了最后的翻译单元,但是我犯了个错误:

    error C3848: expression having type 'const `anonymous-namespace'::ElementAccumulator<T,BinaryFunction>' would lose some const-volatile qualifiers in order to call 'void `anonymous-namespace'::ElementAccumulator<T,BinaryFunction>::operator ()(const point::Point &,const int &)'
            with
            [
                T=SideCounter,
                BinaryFunction=std::plus<int>
            ]
            c:\program files (x86)\microsoft visual studio 9.0\vc\include\functional(324) : while compiling class template member function 'void std::binder2nd<_Fn2>::operator ()(point::Point &) const'
            with
            [
                _Fn2=`anonymous-namespace'::ElementAccumulator<SideCounter,std::plus<int>>
            ]
            c:\users\****\documents\visual studio 2008\projects\TAKE_OVER_THE_WORLD\grid_divider.cpp(361) : see reference to class template instantiation 'std::binder2nd<_Fn2>' being compiled
            with
            [
                _Fn2=`anonymous-namespace'::ElementAccumulator<SideCounter,std::plus<int>>
            ]
    

    我查了一下 binder2nd 它就在那里:它需要一个 const 自适应二进制函数。

    所以,没什么大不了的,我想。我刚用过 boost::bind 相反,对吧?

    错了!现在我的“接管世界”程序需要很长时间才能编译( bind 是在一个模板里面使用的,这个模板被实例化了很多次)!以这种速度,我的天敌将首先占领世界!我不能让这发生——他使用Java!

    有人能告诉我为什么要做这个设计决定吗?这似乎是个奇怪的决定。我想我得把我班的一些内容 mutable 现在…

    编辑:违规代码:

    template <typename T, typename BinaryFunction>
    class ElementAccumulator 
        : public binary_function<typename T::key_type, typename T::mapped_type, void>
    {
    public:
        typedef T MapType;
        typedef typename T::key_type KeyType;
        typedef typename T::mapped_type MappedType;
        typedef BinaryFunction Func;
    
        ElementAccumulator(MapType& Map, Func f) : map_(Map), f_(f) {}
    
        void operator()(const KeyType& k, const MappedType& v)
        {
            MappedType& val = map_[k];
            val = f_(val, v);
        }
    private:
        MapType& map_;
        Func f_;
    };
    
    void myFunc(int n)
    {
        typedef boost::unordered_map<Point, int, Point::PointHash> Counter;
        Counter side_count;
        ElementAccumulator<SideCounter, plus<int> > acc(side_count, plus<int>());
    
            vector<Point> pts = getPts();
        for_each(pts.begin(), pts.end(), bind2nd(acc, n));
    }
    
    3 回复  |  直到 7 年前
        1
  •  5
  •   Alex Martelli    14 年前

    binder2nd 系数取常数 参考 AdaptableBinaryFunction —— const 自适应二进制函数 就其本身而言。你的实例化代码怎么样?一个人通常不会明确提到 粘合剂2 而是通过便利功能工作 bind2nd (这只适用于第二个论点 x 用一个 typename Operation::second_argument_type(x) 或者类似的)。

        2
  •  0
  •   Steve Jessop    14 年前

    好吧,尝试一些推论:

    任何事情都需要一个警察做任何事,是为了允许某人把任何东西传给一个警察。

    最明显的const要传递给“functional”函数的是对临时函数的引用。

    特别是,如果 bind1st 还有其他的东西 <functional> 获取了一个非常量引用参数,然后无法将它们链接在一起以函数样式编程。函数样式讨厌在一条语句中捕获变量中的临时变量,然后在“下一条”语句中“稍后”修改该变量。所有这些都是非常必要和副作用。

    不幸的是,这意味着 <功能性> 定义了, operator() 在这种情况下,函子的数量必须是常量,可能还有其他一些情况。你的不是。

    boost::bind是否允许 const 或者不作为相关模板类型的一部分?如果是,那么也许 <功能性> 这不仅仅是因为boost::bind是在人们对如何从模板中获得最佳效果有了更多想法之后设计的。或者也许 绑定1 是以一种更纯粹的功能性思维设计的,因此没有副作用,所以为什么一切都不应该是恒定的?我可能遗漏了问题的一部分——我从您的代码示例中看到了为什么要使用参数绑定,但我不认为很明显 <功能性> 是寻找任何累加器的正确地点;-)

        3
  •  0
  •   Potatoswatter R. Martinho Fernandes    7 年前

    bind (和旧的,弃用的 bind1st bind2nd )是价值语义。返回对象是自包含的,它不引用参数, const 或者不。

    要获取引用语义,请传递 std::ref 绑定 .

    auto defer_by_value = std::bind( fun, foo, bar ); // Copy fun, foo, and bar.
    
    auto defer_by_ref = std::bind( std::ref( fun ), std::ref( foo ), std::ref( bar ) );
                                                      // Observe fun, foo, and bar.