#pragma once #include #include #include #include #include namespace c10 { namespace guts { /** * Access information about result type or arguments from a function type. * Example: * using A = function_traits::return_type // A == int * using A = function_traits::parameter_types::tuple_type * // A == tuple */ template struct function_traits { static_assert( !std::is_same::value, "In function_traits, Func must be a plain function type."); }; template struct function_traits { using func_type = Result(Args...); using return_type = Result; using parameter_types = typelist::typelist; static constexpr auto number_of_parameters = sizeof...(Args); }; /** * infer_function_traits: creates a `function_traits` type for a simple * function (pointer) or functor (lambda/struct). Currently does not support * class methods. */ template struct infer_function_traits { using type = function_traits< c10::guts::detail::strip_class_t>; }; template struct infer_function_traits { using type = function_traits; }; template struct infer_function_traits { using type = function_traits; }; template using infer_function_traits_t = typename infer_function_traits::type; /** * make_function_traits: creates a `function_traits` type given a Return type * and a typelist of Argument types * * Example: * bool f(int, int); * * infer_function_traits_t == make_function_traits_t> */ template struct make_function_traits { static_assert( false_t::value, "In guts::make_function_traits, the ArgList argument must be typelist<...>."); }; template struct make_function_traits> { using type = function_traits; }; template using make_function_traits_t = typename make_function_traits::type; /** * Use extract_arg_by_filtered_index to return the i-th argument whose * type fulfills a given type trait. The argument itself is perfectly forwarded. * * Example: * std::string arg1 = "Hello"; * std::string arg2 = "World"; * std::string&& result = extract_arg_by_filtered_index(0, * arg1, 2.0, std::move(arg2)); * * Warning: Taking the result by rvalue reference can cause segfaults because * ownership will not be passed on from the original reference. The original * reference dies after the expression and the resulting */ namespace detail { template < template class Condition, size_t index, class Enable, class... Args> struct extract_arg_by_filtered_index_; template < template class Condition, size_t index, class Head, class... Tail> struct extract_arg_by_filtered_index_< Condition, index, std::enable_if_t::value>, Head, Tail...> { static decltype(auto) call(Head&& /*head*/, Tail&&... tail) { return extract_arg_by_filtered_index_:: call(std::forward(tail)...); } }; template < template class Condition, size_t index, class Head, class... Tail> struct extract_arg_by_filtered_index_< Condition, index, std::enable_if_t::value && index != 0>, Head, Tail...> { static decltype(auto) call(Head&& /*head*/, Tail&&... tail) { return extract_arg_by_filtered_index_:: call(std::forward(tail)...); } }; template