Krótka wersja mojego pytania brzmi: jak mogę użyć czegoś takiego jak std::bind()
ze standardowym algorytmem bibliotecznym?Jak "std :: bind()" standardowy algorytm biblioteki?
Ponieważ krótka wersja jest nieco pozbawione szczegółów, tutaj jest trochę wyjaśnienie: Załóżmy, że mam algorytmów std::transform()
i teraz chcę zaimplementować std::copy()
(tak, zdaję sobie sprawę, że istnieje std::copy()
w bibliotece standard C++). Ponieważ jestem okropnie leniwy, wyraźnie chcę użyć istniejącej implementacji std::transform()
. Mógłbym, oczywiście, to zrobić:
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());
}
Jakoś ta implementacja nieco czuje się jak konfiguracji algorytmu. Na przykład, wydaje się, jakby std::bind()
powinien być w stanie wykonać zadanie, ale po prostu za pomocą std::bind()
nie działa:
namespace P = std::placeholders;
auto copy = std::bind(std::transform, P::_1, P::_2, P::_3, identity());
Problem polega na tym, że kompilator nie może określić odpowiednie argumenty szablonów jedynie z algorytmem i nie ma znaczenia, czy istnieje &
, czy też nie. Czy jest coś, co może zrobić takie podejście, jak przy użyciu pracy std::bind()
? Ponieważ jest to oczekiwane, jestem zadowolony z rozwiązania współpracującego z wszystkim, co jest już proponowane do włączenia do standardu C++. Ponadto, aby uciec się od lenistwa, cieszę się, że mogę trochę popracować, aby później łatwiej było z niego korzystać. Pomyśl o tym w ten sposób: w mojej roli jako projektanta biblioteki , będę układał rzeczy raz tak, że każda biblioteka może być leniwy: Jestem pracowitym implementatorem, ale leniwym użytkownikiem.
Jeśli chcesz mieć gotowe łóżko testowe: tutaj jest kompletny 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";
}
@ πάνταῥεῖ: Hej - to prawdziwe pytanie ...! (jasne, podwójne cele odgrywają pewną rolę) –
Połączenie tagów było, co mnie podejrzewało ;-) ... (i to jest oczywiście dobre pytanie) –
Generyczne lambdy to jedyna rzecz, o której mogę pomyśleć, ale Zakładam, że jest niewystarczająco "bind"-like ... –