#pragma once

#define FORWARD_ARGUMENT_SINGLE_ITER_M(Z, N, PREFIX) BOOST_PP_COMMA_IF(N) FORWARD_ARGUMENT_SINGLE(PREFIX ## N)
#define FORWARD_ARGUMENT_SINGLE(NAME) std::forward<decltype(NAME)>(NAME)

#define NAMED_ARGUMENT_SINGLE(T, NAME) typename std::type_identity<T>::type NAME
#define ADD_NAMED_ARGUMENT(Z, I, ARGSTYPE_TUPLE) NAMED_ARGUMENT_SINGLE(BOOST_PP_TUPLE_ELEM(I, ARGSTYPE_TUPLE), BOOST_PP_CAT(x, BOOST_PP_DEC(I)))
#define NAMED_ARGUMENT(...) BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1), (), (BOOST_PP_ENUM_SHIFTED(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), ADD_NAMED_ARGUMENT, (__VA_ARGS__))))
#define NAMED_ARGUMENT_THIS(THISCLASS, ...) BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1), (THISCLASS *that), (THISCLASS *that, BOOST_PP_ENUM_SHIFTED(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), ADD_NAMED_ARGUMENT, (__VA_ARGS__))))

#define NAMED_ARG_FN_DECL(...) auto BOOST_PP_VARIADIC_ELEM(0, __VA_ARGS__) NAMED_ARGUMENT(__VA_ARGS__)