#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;
}