2

I recently encountered this use of for_each:

std::for_each(ts.begin(), ts.end(), [=](T& t){t *= f;});

Well, it works. For a container of Ts and a T f, this multiplies each value by f. However I dislike the use of the lambda here. It's short, but it seems to me that it only duplicates std::multiplies. Additionally, it shouldn't be for_each, but transform, to express the intent of modifying.

However, std::multiplies is a binary predicate, std::transform requires a unary predicate.

I tried to bind f as one parameter, but apparently I'm using it wrong:

std::transform(ts.begin(), ts.end(), std::bind(std::multiplies<T>(), f));

GCC tries to give me a hint with the error message, but I don't see the actual cause:

no matching function for call to ‘transform(std::vector<int>::iterator, std::vector<int>::iterator, std::_Bind_helper<false, std::multiplies<int>, const int&>::type)’

I suspect that I'm using std::bind wrong. What is my mistake?

stefan
  • 10,215
  • 4
  • 49
  • 90
  • `for(auto& t : ts) t *= f; // wheee~` – Xeo Sep 10 '13 at 22:30
  • @Xeo, yes "wheee" indeed. Sadly, g++-4.5 has problems with the colon.. So as I need to get this version compatible => std algorithms. Additionally, I recently watched (and liked) GN13s "Seasoning" talk by Sean Parent. No raw loops! – stefan Sep 11 '13 at 06:13
  • Did you also watch it carefully? He mentioned that short range-for loops are fine, since there's way less clutter than with algorithms with the iterator stuff. :) – Xeo Sep 11 '13 at 06:14
  • @Xeo: Of course I did. But if we _can't_ use a range-based loop, we would need a for loop with iterators (and dereference stuff, ugly!) or an index-based loop (why introduce a seemingly unrelated variable? ugly ugly). Both I think look worse than an algorithm. In a perfect world, I would stick with range-based for I think (though the one-liner algorithms are pretty as well). – stefan Sep 11 '13 at 06:49

1 Answers1

4

You forgot the iterator for result range and a placeholder in bind-expression:

std::transform(
    ts.begin(), ts.end(), // source range
    ts.begin(),           // beginning of result range
    std::bind(std::multiplies<int>(), f, std::placeholders::_1) );
    //                                   ^^^^^^^^^^^^^^^^^^^^^
    //                                   this is where the value from
    //                                   dereferenced source iterator go
jrok
  • 54,456
  • 9
  • 109
  • 141
  • And *this* is why `std::transform` is not *that* awesome for such things. ;) It's functional-style, not modifying the sequence in-place unless asked to. – Xeo Sep 10 '13 at 22:30