Boost logo

Boost :

Subject: Re: [boost] [Bind] Interoperability of bind/mem_fn with transform_iterator
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2010-05-03 12:45:02


On Mon, May 3, 2010 at 5:48 AM, Samuel Debionne <debionne_at_[hidden]> wrote:
>> On Fri, Apr 30, 2010 at 3:37 AM, Samuel Debionne<debionne_at_[hidden]>
>>  wrote:
>>>
>>> Hello all,
>>> I'm scratching my head about the correct way to use transform_iterator
>>> with
>>> bind and mem_fn. In brief, bind and mem_fn return object functions that
>>> are
>>> not Default Constructible, which means that, when used to construct a
>>> transform_iterator, the resulting transform_iterator is not even a
>>> Trivial
>>> Iterator.
>>>
>>> Most of the case, it's not a problem because the transform_iterator is
>>> never
>>> default constructed... until some libs that do concept checking on their
>>> template parameters are used. See the following code for exemple :
>>
>> Right, mem_fn_t is not DefaultConstructible, so a transform_iterator
>> with mem_fn_t does not model ForwardTraversalIterator. Likewise with
>> the return type of bind, which c++0x requires to be MoveConstructible
>> (and CopyConstructible when it's args are) but not
>> DefaultConstructible. In your specific example, however, you can still
>> build a valid ForwardTraversalIterator by using boost::function to
>> erase the return type of mem_fn. The same should work with bind.
>>
>>  check(make_transform_iterator(
>>    foo_vec.begin(), function<size_t(foo&)>(mem_fn(&foo::get_id))));
>>
>>  check(make_transform_iterator(
>>    foo_vec.begin(), function<size_t(foo&)>(mem_fn(&foo::id_))));
>>
>> Daniel Walker
>
> Daniel, thank you for your solution. But doesn't type erasure avoid some
> optimisations to take place (inlining) ?

Not necessarily. All of boost::function can be inlined. I suppose
results may vary according to your particular compiler's optimization
strategy, but it is not immediately clear to me that boost::function
precludes any optimizations.

> That could be a problem since the
> function is called each time the iterator is deferred. I just did some
> benchmarking that consists in accumulating a large range of foo id. Here are
> the results with vc10 :
>
> Boost.Function vs Hand Written : 9 time slower
> Boost.MemFn vs Hand Written : 3.7 time slower
> Boost.Function vs Boost.MemFn : 1.6 time slower

A code sample that demonstrates these performance changes would be
more informative.

>
> Anyway, in my opinion, using bind/mem_fn/lambda with transform_iterator is a
> common use case. That would be great to have an option to add a default
> constructor in those libs... or is it to risky ?

Well, the downside of default constructible call wrappers is that
certain errors are hard to detect prior to runtime; i.e. a default
constructed call wrapper would throw a bad_function_call when invoked.
When you use a mem_fn or bind object, you know you won't get those
sorts of exceptions at runtime, since neither are default
constructible. However, boost::function _is_ default constructible.
Consequentially, it gives users a way to make that trade-off in some
situations; i.e to sacrifice some compile time error detection in
favor of more runtime error detection. With respect to
transform_iterator, boost::function can bridge the conceptual gap
between non-default constructible call wrappers and iterators, which
are necessarily default constructible.

Daniel Walker


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