#pragma once // // function_traits.hpp // // Deduces the return type and argument-type pack of "anything callable": // plain free-function pointers, non-generic lambdas (captureless or // capturing), and std::function instances. This is what lets // Command::action() figure out, at compile time, exactly which C++ types // it needs to convert parsed CLI tokens into -- without the user ever // having to spell the types out twice. // #include #include #include namespace cliforge::detail { template struct function_traits; // Plain free function: void foo(std::string, int) template struct function_traits { using return_type = Ret; static constexpr std::size_t arity = sizeof...(Args); template using arg = std::tuple_element_t>; using args_tuple = std::tuple; }; // std::function template struct function_traits> { using return_type = Ret; static constexpr std::size_t arity = sizeof...(Args); template using arg = std::tuple_element_t>; using args_tuple = std::tuple; }; // Pointer-to-member-function of operator(), const and non-const, used to // peel apart lambdas (which are just anonymous functors under the hood). template struct function_traits { using return_type = Ret; static constexpr std::size_t arity = sizeof...(Args); template using arg = std::tuple_element_t>; using args_tuple = std::tuple; }; template struct function_traits { using return_type = Ret; static constexpr std::size_t arity = sizeof...(Args); template using arg = std::tuple_element_t>; using args_tuple = std::tuple; }; // Fallback: any other callable (lambda, functor) -- peel off operator(). template struct function_traits : function_traits {}; } // namespace cliforge::detail