#pragma once #include "function.hpp" #include <utility> template <typename> struct remove_cv_seq; template <typename Return, typename... Args> struct remove_cv_seq<Return(Args...)> { using type = Return(Args...); }; template <typename Return, typename... Args> struct remove_cv_seq<Return(Args...) const> { using type = Return(Args...); }; template <typename Return, typename... Args> struct remove_cv_seq<Return(Args...) &> { using type = Return(Args...); }; template <typename Function> constexpr inline auto extract_signature(Function * /*unused*/) noexcept { return Signature<typename remove_cv_seq<Function>::type>(); } template <typename Class, typename Function> constexpr inline auto extract_signature(Function Class::* /*unused*/) noexcept { return Signature<typename remove_cv_seq<Function>::type>(); } template <typename Function> constexpr inline auto extract_signature(Function const & /*unused*/) noexcept -> decltype(&Function::operator(), extract_signature(&Function::operator())) { return extract_signature(&Function::operator()); } template <typename Function, typename Return, typename... Args> inline auto get_normalized_lambda(Function &&func, Signature<Return(Args...)> /*unused*/) noexcept { // Static copy of func. This will make it accessible for the lambda without using a // lamda capture static auto static_func = Function(std::forward<Function>(func)); return +[](Args... args) noexcept( noexcept(std::declval<Function>()(std::forward<Args>(args)...))) -> Return { return static_func(std::forward<Args>(args)...); }; } /** * Normalizes the type signature of a lambda function. * * This will make a lambda with captures passable to other functions. * * @param func A lambda function * @returns The lambda function normalized. */ template <typename Function> constexpr auto normalize_lambda(Function &&func) noexcept { return get_normalized_lambda(std::forward<Function>(func), extract_signature(std::forward<Function>(func))); }