Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2001-08-16 05:38:45


From: "Ross Smith" <ross.s_at_[hidden]>
> There's an example under "Using bind with function pointers" that I'm
> pretty sure contains a typo:
>
> > bind covers the functionality of std::bind2nd as well:
> >
> > std::bind2nd(std::ptr_fun(f), 5)(x); // f(5, x)
> > bind(f, 5, _2)(x); // f(5, x)
>
> Unless I've completely misunderstood the way the placeholders are
> supposed to work, the third argument in the last line should be _1.

Someone that actually reads the docs. :-) You are right, of course.

> Under "Using bind with member function pointers", I don't understand one
> of the examples:
>
> > bind(&X::f, &x, _1)(i); // (&x)->f(i)
>
> Is this meant to imply that a pointer passed where the object is
> expected will automatically be dereferenced when the function is called?

No, bind does not dereference pointers. The reason this works is that

bind(&X::f, &x, _1)

is actually a shortcut form for

bind<R>(mem_fun(&X::f), &x, _1)

and it's the function object returned from mem_fun that is able to handle a
pointer or a reference to X as a first argument.

> I really dislike the "_number" notation for placeholders. First, it
> doesn't stand out -- it looks too much like an ordinary integer
> argument. (This is particularly confusing in the examples in the
> documentation, where most of the arguments _are_ integers.) In addition
> to the visual confusion, this also means that they're only one very
> small typo away from a bug that could be very hard to track down.

Ironically, _1 has evolved from the more traditional 'boost::arg1' notation.
:-)

The "perfect" syntax for a bound function is:

f($2, $1)

or

f(%2, %1)

depending on what skool you're from. [Likewise $1 + $2 for lambda(x, y)(x +
y).]

The closest I was able to get in C++ was

bind(f, _2, _1).

In my experience, the _1 notation really stands out and is not easily
confused with either 1 or -1. In contrast,

bind(f, arg2, arg1)

is less readable for someone that's not "in the know" - arg1 and arg2 are
pretty ordinary identifiers; the person will lose several minutes looking
for the variables named argN.

> Second, leading underscores are dangerous. Practically everyone agrees
> on that.

In general, yes, they are dangerous. In this particular case I think we're
pretty safe, though. :-)

> That applies to the implementation as well; a quick look at bind.hpp
> revealed far too many leading underscores for my peace of mind. If they

You aren't supposed to look at implementation details. :-)

> were long names it wouldn't be quite so bad, but they include names like
> _bi and _int -- again, exactly the sort of thing that some idiot is

_int will change.

_bi, on the other hand, is an intentional compromise. I want a short name
for the implementation details namespace for two reasons: first, it makes
the code easier to read, and second, it makes the error messages easier to
read. The last part is quite important, since the errors generated by, for
instance,

bind(f, 5, _2)(x);

are pretty long even with the short _bi.

On the other hand, I can't simply use some short name since this goes into
boost::, and boost:: is already getting too crowded (boost::detail even more
so.) So I settled on _bi.

> likely to have used as a macro somewhere deep in the bowels of
> <windows.h> or <unistd.h>. Please, _please_ do something about this.

I'm willing to take the risk. Nobody is safe from macros (pascal, min,
Sleep.) Of course if someone does report a conflict, _bi will change.

--
Peter Dimov
Multi Media Ltd.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk