Why do bind1st and bind2nd require constant function objects?
So, I was writing a C++ program which would allow me to take control of the entire world. I was all done writing the final translation unit, but I got an error:
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>' bei开发者_如何学Pythonng compiled
with
[
_Fn2=`anonymous-namespace'::ElementAccumulator<SideCounter,std::plus<int>>
]
I looked in the specifications of binder2nd
and there it was: it took a const
AdaptibleBinaryFunction.
So, not a big deal, I thought. I just used boost::bind
instead, right?
Wrong! Now my take-over-the-world program takes too long to compile (bind
is used inside a template which is instantiated quite a lot)! At this rate, my nemesis is going to take over the world first! I can't let that happen -- he uses Java!
So can someone tell me why this design decision was made? It seems like an odd decision. I guess I'll have to make some of the elements of my class mutable
for now...
EDIT: The offending code:
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));
}
binder2nd
ctor takes a constant reference to an AdaptableBinaryFunction
-- not a const
AdaptableBinaryFunction
per se. How's your instantiating-code? One normally doesn't explicitly mention binder2nd
but rather work through convenience function bind2nd (which simply works on the second argument x
with a typename Operation::second_argument_type(x)
or the like).
Well, attempting some deduction:
The reason anything takes a const anything, is to permit someone to pass a const anything into it.
The most obvious const something that you want to pass into "functional" functions is a reference to a temporary.
In particular, if bind1st
and other stuff in <functional>
took a non-const reference parameter, then you couldn't chain them together to program in a functional style. A functional style abhors the idea of capturing a temporary in a variable in one statement, and then "later" modifying that variable in "the next" statement. All very imperative and side-effecty.
Unfortunately, this means that as <functional>
is defined, operator()
of functors needs to be const in this case and presumably a bunch of other cases. Yours isn't.
Does boost::bind allow either const
or not as part of the template type where relevant? If so then maybe <functional>
doesn't do this simply because boost::bind was designed once people had more idea how to get the best out of templates. Or maybe bind1st
was designed with a purer functional mindset, hence no side-effects, hence why shouldn't everything be const? I may have missed part of the point of the question - I see from your code example why you want to use parameter binding, but I don't think it's obvious that a header called <functional>
is the right place to look for anything involving accumulators ;-)
bind
(and the old, deprecated bind1st
and bind2nd
) are value-semantic. The return object is self-contained and it doesn't reference the parameters, const
or not.
To get reference semantics instead, pass std::ref
to 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.
精彩评论