#include <iostream>
#include <tuple>
#include <cassert>
#include <functional>
using namespace std;
struct invoke_fn
{
template <typename F, typename ... As>
constexpr decltype(auto) operator () (F && f, As && ... as) const
{
return std::forward<F>(f)(std::forward<As>(as)...);
}
};
constexpr auto invoke = invoke_fn{};
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl( F&& f, Tuple&& t, std::index_sequence<I...> )
{
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{});
}
struct forward_as_tuple_fn
{
template <typename ... Ts>
constexpr decltype(auto) operator () (Ts && ... ts) const
{
return std::forward_as_tuple(std::forward<Ts>(ts)...);
}
};
constexpr auto forward_as_tuple1 = forward_as_tuple_fn{};
template <typename T>
constexpr decltype(auto) forward_tuple (T && t)
{
return apply(forward_as_tuple1, std::forward<T>(t));
}
template<typename ...As>
constexpr decltype(auto) part(As && ...as)
{
return [as = std::make_tuple(std::forward<As>(as)...)](auto && ...as2)
{
return apply(invoke, std::tuple_cat(forward_tuple(as), std::forward_as_tuple(as2...)));
};
}
struct Caller
{
Caller() = default;
Caller(const Caller&) { std::cout << "copy" << std::endl; }
Caller(Caller&&) { std::cout << "move" << std::endl; }
template <typename T>
auto operator () (T t) const
{
}
};
int main()
{
auto c = Caller();
// только одно копирование, при создание объекта part, при создание кортежа.
part(c)(3.14);
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dHVwbGU+CiNpbmNsdWRlIDxjYXNzZXJ0PgojaW5jbHVkZSA8ZnVuY3Rpb25hbD4KdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCnN0cnVjdCBpbnZva2VfZm4KewogICAgdGVtcGxhdGUgPHR5cGVuYW1lIEYsIHR5cGVuYW1lIC4uLiBBcz4KICAgIGNvbnN0ZXhwciBkZWNsdHlwZShhdXRvKSBvcGVyYXRvciAoKSAoRiAmJiBmLCBBcyAmJiAuLi4gYXMpIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuIHN0ZDo6Zm9yd2FyZDxGPihmKShzdGQ6OmZvcndhcmQ8QXM+KGFzKS4uLik7CiAgICB9Cn07CmNvbnN0ZXhwciBhdXRvIGludm9rZSA9IGludm9rZV9mbnt9OwoKdGVtcGxhdGUgPGNsYXNzIEYsIGNsYXNzIFR1cGxlLCBzdGQ6OnNpemVfdC4uLiBJPgpjb25zdGV4cHIgZGVjbHR5cGUoYXV0bykgYXBwbHlfaW1wbCggRiYmIGYsIFR1cGxlJiYgdCwgc3RkOjppbmRleF9zZXF1ZW5jZTxJLi4uPiApCnsKICByZXR1cm4gc3RkOjpmb3J3YXJkPEY+KGYpKHN0ZDo6Z2V0PEk+KHN0ZDo6Zm9yd2FyZDxUdXBsZT4odCkpLi4uKTsKfQoKdGVtcGxhdGUgPGNsYXNzIEYsIGNsYXNzIFR1cGxlPgpjb25zdGV4cHIgZGVjbHR5cGUoYXV0bykgYXBwbHkoRiYmIGYsIFR1cGxlJiYgdCkKewogICAgcmV0dXJuIGFwcGx5X2ltcGwoc3RkOjpmb3J3YXJkPEY+KGYpLCBzdGQ6OmZvcndhcmQ8VHVwbGU+KHQpLAogICAgICAgIHN0ZDo6bWFrZV9pbmRleF9zZXF1ZW5jZTxzdGQ6OnR1cGxlX3NpemU8c3RkOjpkZWNheV90PFR1cGxlPj46OnZhbHVlPnt9KTsKfQoKc3RydWN0IGZvcndhcmRfYXNfdHVwbGVfZm4KewogICAgdGVtcGxhdGUgPHR5cGVuYW1lIC4uLiBUcz4KICAgIGNvbnN0ZXhwciBkZWNsdHlwZShhdXRvKSBvcGVyYXRvciAoKSAoVHMgJiYgLi4uIHRzKSBjb25zdAogICAgewogICAgICAgIHJldHVybiBzdGQ6OmZvcndhcmRfYXNfdHVwbGUoc3RkOjpmb3J3YXJkPFRzPih0cykuLi4pOwogICAgfQp9OwoKY29uc3RleHByIGF1dG8gZm9yd2FyZF9hc190dXBsZTEgPSBmb3J3YXJkX2FzX3R1cGxlX2Zue307Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY29uc3RleHByIGRlY2x0eXBlKGF1dG8pIGZvcndhcmRfdHVwbGUgKFQgJiYgdCkKewogICAgcmV0dXJuIGFwcGx5KGZvcndhcmRfYXNfdHVwbGUxLCBzdGQ6OmZvcndhcmQ8VD4odCkpOwp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSAuLi5Bcz4KY29uc3RleHByIGRlY2x0eXBlKGF1dG8pIHBhcnQoQXMgJiYgLi4uYXMpCnsgICAKICAgIHJldHVybiBbYXMgPSBzdGQ6Om1ha2VfdHVwbGUoc3RkOjpmb3J3YXJkPEFzPihhcykuLi4pXShhdXRvICYmIC4uLmFzMikKICAgIHsKICAgICAgICByZXR1cm4gYXBwbHkoaW52b2tlLCBzdGQ6OnR1cGxlX2NhdChmb3J3YXJkX3R1cGxlKGFzKSwgc3RkOjpmb3J3YXJkX2FzX3R1cGxlKGFzMi4uLikpKTsKICAgIH07Cn0KCgpzdHJ1Y3QgQ2FsbGVyCnsKCUNhbGxlcigpID0gZGVmYXVsdDsKCUNhbGxlcihjb25zdCBDYWxsZXImKSB7IHN0ZDo6Y291dCA8PCAiY29weSIgPDwgc3RkOjplbmRsOyB9CglDYWxsZXIoQ2FsbGVyJiYpIHsgc3RkOjpjb3V0IDw8ICJtb3ZlIiA8PCBzdGQ6OmVuZGw7IH0KCQoJdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CiAgICBhdXRvIG9wZXJhdG9yICgpIChUIHQpIGNvbnN0CiAgICB7CiAgICAJCiAgICB9Cn07CiAgICAKICAgIAppbnQgbWFpbigpIAp7CglhdXRvIGMgPSBDYWxsZXIoKTsKCS8vINGC0L7Qu9GM0LrQviDQvtC00L3QviDQutC+0L/QuNGA0L7QstCw0L3QuNC1LCDQv9GA0Lgg0YHQvtC30LTQsNC90LjQtSDQvtCx0YrQtdC60YLQsCBwYXJ0LCDQv9GA0Lgg0YHQvtC30LTQsNC90LjQtSDQutC+0YDRgtC10LbQsC4KCXBhcnQoYykoMy4xNCk7CglyZXR1cm4gMDsKfQ==