lundi 29 décembre 2014

How to `std::bind()` a standard library algorithm?

The short version of my question is this: How can I use something like std::bind() with a standard library algorithm?


Since the short version is a bit devoid of details, here is a bit of an explanation: Assume I have the algorithms std::transform() and now I want to implement std::copy() (yes, I realize that there is std::cpopy() in the standard C++ library). Since I'm hideously lazy, I clearly want to use the existing implementation of std::transform(). I could, of course, do this:



struct identity {
template <typename T>
auto operator()(T&& value) const -> T&& { return std::forward<T>(value); }
};
template <typename InIt, typename OutIt>
auto copy(InIt begin, InIt end, OutIt to) -> OutIt {
return std::transform(begin, end, to, identity());
}


Somehow this implementation somewhat feels like a configuration of an algorithm. For example, it seems as if std::bind() should be able to do the job but simply using std::bind() doesn't work:



namespace P = std::placeholders;
auto copy = std::bind(std::transform, P::_1, P::_2, P::_3, identity());


The problem is that the compiler can't determine the appropriate template arguments from just the algorithm and it doesn't matter if there is an & or not. Is there something which can make an approach like using std::bind() work? Since this is looking forward, I'm happy with a solution working with anything which is already proposed for inclusion into the C++ standard. Also, to get away with my laziness I'm happy to do some work up front for later easier use. Think of it this way: in my role as a library implementer, I'll put things together once such that every library user can be lazy: I'm a busy implementer but a lazy user.


In case you want to have a ready-made test bed: here is a complete program.



#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <utility>
#include <vector>

using namespace std::placeholders;

struct identity {
template <typename T>
T&& operator()(T&& value) const { return std::forward<T>(value); }
};


int main()
{
std::vector<int> source{ 0, 1, 2, 3, 4, 5, 6 };
std::vector<int> target;

#ifdef WORKS
std::transform(source.begin(), source.end(), std::back_inserter(target),
identity());
#else
// the next line doesn't work and needs to be replaced by some magic
auto copy = std::bind(&std::transform, _1, _2, _3, identity());
copy(source.begin(), source.end(), std::back_inserter(target));
#endif
std::copy(target.begin(), target.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n";
}

Aucun commentaire:

Enregistrer un commentaire