
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 :
I meant to say deferenced, not defered. But I think you understood.
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.
I attached the code that produces these numbers. I compiled the code with visual studio express 2010 in release mode with the default options. The benchmark accumulates a range of number, where the numbers are accessed through a member function (see class foo). The following versions are compared : 1. hand written loop 2. std::accumulate with hand written member function call wrapper 3. std::accumulate with boost::mem_fn call wrapper 4. std::accumulate with boost::function call wrapper 5. std::for_each with a c0x lambda There are a few interesting things : - 1, 2, 5 are the fastest (about the same speed) - using boost::mem_fn (3) really makes a difference (3 times slower) - using boost::function (4) makes things a little bit worse (4.5 times slower)
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.
So, boost::function is definitely the solution. In the context of transform_iterator, it could be interesting to "systematically" wrap unary function objects that have no trivial constructor with boost::function so that the resulting iterator models the expected concept. A proposed implementation that uses the has_trivial_constructor trait is in the attached file. What about a warning in the usage section of the documentation of transform_iterator ? Samuel Debionne