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

时间:2010-05-09 00:59:11

标签: c++ templates stl

所以,我正在写一个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 AdaptibleBinaryFunction。

所以,我想,这不是什么大不了的事。我只是使用了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 个答案:

答案 0 :(得分:5)

binder2nd ctor对AdaptableBinaryFunction - 而不是 const AdaptableBinaryFunction本身采用引用 。你的实例化代码怎么样?一个人通常没有明确提到binder2nd,而是通过便利函数bind2nd(它只适用于第二个参数xtypename Operation::second_argument_type(x)等)。

答案 1 :(得分:0)

好吧,尝试一些演绎:

任何东西取任何东西的原因是允许某人将const传递给它。

您希望传递给“功能”函数的最明显的const是对临时函数的引用。

特别是,如果bind1st<functional>中的其他内容采用非const引用参数,则无法将它们链接在一起以函数样式进行编程。功能样式憎恶在一个语句中捕获变量中的临时值的想法,然后“稍后”在“下一个”语句中修改该变量。所有非常迫切和副作用。

不幸的是,这意味着在定义<functional>时,operator()的仿函数在这种情况下需要是const,大概是其他一些情况。你的不是。

boost :: bind是否允许const或者不作为模板类型的一部分?如果是这样,那么<functional>可能不会这么做,因为一旦人们更多地了解如何充分利用模板,就会设计boost :: bind。或许bind1st的设计具有更纯粹的功能性思维,因此没有副作用,因此为什么一切都不应该是常量?我可能已经错过了问题的一部分 - 我从你的代码示例中看到了为什么要使用参数绑定,但我认为很明显,名为<functional>的标题是寻找的正确位置涉及累加器的任何事情; - )

答案 2 :(得分:0)

bind(旧的,已弃用的bind1stbind2nd)具有价值语义。返回对象是自包含的,它不会引用参数const,而不是{。}}。

要获取引用语义,请将std::ref传递给bind

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.