#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_TRAITS_HPP #define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_TRAITS_HPP #include "traits.hpp" #include "single.hpp" #include "injected.hpp" #include "invoke.hpp" #include "container_service.hpp" #ifdef _MSC_VER #ifndef __clang__ #define KGR_KANGARU_MSVC_NO_AUTOCALL_MAP_CHECK #endif // !__clang__ #endif // _MSC_VER #if _MSC_VER == 1900 #ifndef __clang__ #define KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD #endif // !__clang__ #endif // _MSC_VER namespace kgr { namespace detail { template using is_container_service = std::is_base_of; template struct is_construct_invokable_helper { private: template static std::false_type test_helper(...); template()(std::declval>()..., std::declval()...)), enable_if_t>::value>...> = 0> static std::true_type test_helper(seq); template static decltype(test_helper(tuple_seq_minus, sizeof...(As)>{})) test(int); template static std::false_type test(...); public: using type = decltype(test(0)); }; template using is_construct_invokable = typename is_construct_invokable_helper::type; template struct has_callable_template_construct : std::false_type {}; template struct has_callable_template_construct< T, meta_list, meta_list, enable_if_t), Args...>::value> > : std::true_type {}; template struct get_template_construct_helper; template struct get_template_construct_helper< T, meta_list<>, meta_list, enable_if_t, meta_list>::value> > {}; template struct get_template_construct_helper< T, meta_list, meta_list, enable_if_t, meta_list>::value> > : get_template_construct_helper, meta_list> {}; template struct get_template_construct_helper< T, meta_list, meta_list, enable_if_t, meta_list>::value> > : std::integral_constant), &T::template construct> {}; template using get_template_construct = get_template_construct_helper, meta_list>; template struct template_construct_exist : std::false_type {}; template struct template_construct_exist, void_t)>> : std::true_type {}; template struct get_any_template_construct_helper; template struct get_any_template_construct_helper< T, meta_list, enable_if_t>::value> > : get_any_template_construct_helper> {}; template struct get_any_template_construct_helper< T, meta_list, enable_if_t>::value> > : std::integral_constant), &T::template construct> {}; template using get_any_template_construct = get_any_template_construct_helper>; template struct has_any_template_construct_helper : std::false_type {}; template struct has_any_template_construct_helper, void_t::value_type>> : std::true_type {}; template using has_any_template_construct = has_any_template_construct_helper>; template struct has_template_construct_helper : std::false_type {}; template struct has_template_construct_helper, void_t::value_type>> : std::true_type {}; template using has_template_construct = has_template_construct_helper>; template struct construct_function_helper { private: template struct get_construct { using type = std::integral_constant; }; template::value && !has_template_construct::value, int> = 0> static get_construct test(); template::value, int> = 0> static get_template_construct test(); using inner_type = decltype(test()); public: using type = typename inner_type::type; }; template struct construct_function_helper {}; template struct has_any_construct { constexpr static bool value = has_any_template_construct::value || has_construct::value; }; template using has_valid_construct = std::integral_constant::value || has_construct::value>; template using construct_function = typename construct_function_helper::value, T, Args...>::type; template using construct_function_t = typename construct_function::value_type; template using construct_result_seq = tuple_seq>>; template struct is_construct_function_callable_helper : std::false_type {}; template struct is_construct_function_callable_helper, enable_if_t, Args...>::value>> : std::true_type {}; template struct is_construct_function_callable_helper, enable_if_t::value || is_abstract_service::value>> : std::true_type {}; template using is_construct_function_callable = is_construct_function_callable_helper>; template class Trait, typename T, typename... Args> struct dependency_trait_helper { template struct expand { using type = Trait>>; }; template>>::type::value>..., enable_if_t::type::value>...> = 0> static std::true_type test(seq); template::value, int> = 0> static std::true_type test_helper(int); template static std::false_type test(...); template static std::false_type test_helper(...); template::value, int> = 0, int_t> = 0> static decltype(test(tuple_seq_minus>, sizeof...(As)>{})) test_helper(int); public: using type = decltype(test_helper(0)); }; template class Trait, typename T, typename... Args> using dependency_trait = typename dependency_trait_helper::type; template struct is_service_constructible_helper { private: template static is_service_instantiable>>, tuple_element_t>>...> test(seq); // This overload is needed for msvc. // Or else it will try to call the one just above with a 0 as S for strange reason. template> = 0> static is_service_instantiable test(seq<>); template::value, int> = 0> static std::true_type test_helper(int); template static std::false_type test(...); template static std::false_type test_helper(...); // The enable if is required here or else the function call will be ambiguous on visual studio. template::value, int> = 0> static decltype(test(tuple_seq>>{})) test_helper(int); public: using type = decltype(test_helper(0)); }; template using is_service_constructible = typename is_service_constructible_helper::type; template struct is_override_service_helper { private: template static std::false_type test(...); template>>::value>...> = 0> static std::true_type test(seq); public: using type = decltype(test(tuple_seq>{})); }; template using is_override_service = typename is_override_service_helper::type; template struct is_override_convertible_helper { private: // This is a workaround for msvc. Expansion in very complex expression // leaves the compiler without clues about what's going on. template struct expander { using type = is_explicitly_convertible, ServiceType>>>; }; template static std::false_type test(...); template static std::false_type test_helper(...); template::type::value>...> = 0> static std::true_type test_helper(seq); template>>::value>...> = 0> static decltype(test_helper(seq{})) test(seq); public: using type = decltype(test(tuple_seq>{})); }; template using is_override_convertible = typename is_override_convertible_helper::type; template struct is_override_services_helper { private: // This is a workaround for msvc. Expansion in very complex expression // leaves the compiler without clues about what's going on. template struct expander { using type = is_service>>; }; template static std::false_type test(...); template static std::false_type test_helper(...); template::type::value>...> = 0> static std::true_type test_helper(seq); template>>::value>...> = 0> static decltype(test_helper(seq{})) test(seq); public: using type = decltype(test(tuple_seq>{})); }; template using is_override_services = typename is_override_services_helper::type; template using is_single_no_args = std::integral_constant::value || meta_list_empty>::value >; template struct is_default_overrides_abstract_helper { private: template static std::false_type test(...); template::value && is_abstract_service::value, int> = 0> static is_overriden_by> test(int); template::value, int> = 0> static std::true_type test(int); public: using type = decltype(test(0)); }; template using is_default_overrides_abstract = typename is_default_overrides_abstract_helper::type; template struct is_default_convertible_helper { private: template static std::false_type test(...); template::value, int> = 0> static is_explicitly_convertible>, ServiceType> test(int); template::value, int> = 0> static std::true_type test(int); public: using type = decltype(test(0)); }; template using is_default_convertible = typename is_default_convertible_helper::type; template using is_default_service_valid = std::integral_constant::value || !has_default::value) && is_default_overrides_abstract::value && is_default_convertible::value >; template using service_check = std::integral_constant::value && is_service_constructible::value && is_construct_function_callable::value && is_default_service_valid::value && is_override_convertible::value && is_override_services::value >; template using dependency_check = std::integral_constant::value && dependency_trait::value && dependency_trait::value && dependency_trait::value && dependency_trait::value && dependency_trait::value >; template class Map, typename T, typename P, typename... Args> struct is_pointer_invokable_helper { private: template().*std::declval())(std::declval>>>()..., std::declval()...))> = 0> static std::true_type test(seq); template static std::false_type test(...); public: using type = decltype(test(tuple_seq_minus, sizeof...(Args)>{})); }; template class Map, typename T, typename P, typename... Args> struct is_pointer_invokable : is_pointer_invokable_helper::type {}; template class, typename, typename, typename, typename = void> struct has_callable_template_call : std::false_type {}; template class Map, typename T, typename... TArgs, typename... Args> struct has_callable_template_call< Map, T, meta_list, meta_list, enable_if_t)), #else decltype(exact(&T::template operator())), #endif // KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD Args...>::value> > : std::true_type {}; template class, typename, typename, typename, typename = void> struct get_template_call_helper; template class Map, typename T, typename... Args> struct get_template_call_helper< Map, T, meta_list<>, meta_list, enable_if_t, meta_list>::value> > {}; template class Map, typename T, typename Head, typename... Tail, typename... Args> struct get_template_call_helper< Map, T, meta_list, meta_list, enable_if_t, meta_list>::value> > : get_template_call_helper, meta_list> {}; template class Map, typename T, typename... TArgs, typename... Args> struct get_template_call_helper< Map, T, meta_list, meta_list, enable_if_t, meta_list>::value> > { #ifdef KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD using type = decltype(exact(&T::operator())); #else using type = decltype(exact(&T::template operator())); #endif // KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD }; template class Map, typename T, typename... Args> using get_template_call = get_template_call_helper, meta_list>; template class, typename, typename, typename = void> struct has_template_call_operator : std::false_type {}; template class Map, typename T, typename... Args> struct has_template_call_operator, void_t::type>> : std::true_type {}; template class Map, typename, typename, typename = void> struct invoke_function_helper {}; template class Map, typename T, typename... Args> struct invoke_function_helper, enable_if_t::value && !has_template_call_operator>::value>> { using type = decltype(&T::operator()); using return_type = function_result_t; using argument_types = function_arguments_t; template using argument_type = meta_list_element_t; }; template class Map, typename T, typename... Args> struct invoke_function_helper, void_t, enable_if_t::value && !has_template_call_operator>::value>>> { using type = T; using return_type = function_result_t; using argument_types = function_arguments_t; template using argument_type = meta_list_element_t; }; template class Map, typename T, typename... Args> struct invoke_function_helper< Map, T, meta_list, enable_if_t::value && has_template_call_operator>::value> > { using type = typename get_template_call::type; using return_type = function_result_t; using argument_types = function_arguments_t; template using argument_type = meta_list_element_t; }; template class Map, typename T, typename... Args> struct invoke_function : invoke_function_helper> {}; template class Map, typename T, typename... Args> using invoke_function_t = typename invoke_function::type; template class Map, typename T, typename... Args> using invoke_function_arguments_t = typename invoke_function::argument_types; template class Map, typename T, typename... Args> using invoke_function_argument_t = typename invoke_function::template argument_type; template class Map, typename T, typename... Args> using invoke_function_result_t = typename invoke_function::return_type; template class Map, typename T, typename... Args> struct is_invokable_helper { private: template struct expand { using type = invoke_function_argument_t; }; // This sub trait is for visual studio // The constraint can be simplified because every argument are simple template argument template struct call_test { private: template static std::false_type test(...); template()(std::declval()...))> = 0> static std::true_type test(int); using type = decltype(test(0)); public: static constexpr bool value = type::value; }; template using map_t = service_map_t; template::type>>..., As...>::value, int> = 0> static std::true_type test_helper(seq); template static std::false_type test_helper(...); template static decltype(test_helper(tuple_seq_minus, sizeof...(Args)>{})) test(int); template static std::false_type test(...); public: using type = decltype(test(0)); }; template class Map, typename T, typename... Args> struct is_invokable : is_invokable_helper::type {}; template class Trait, typename T> struct autocall_trait_helper { private: template struct expand { using type = Trait>; }; template static std::false_type test_helper(...); template::type::value>...> = 0> static std::true_type test_helper(seq); template static std::true_type test(...); template static decltype(test_helper(detail::tuple_seq{})) test(int); public: using type = decltype(test(0)); }; template class Trait, typename T> using autocall_trait = typename autocall_trait_helper::type; template struct is_autocall_entry_map_complete_helper { #ifndef KGR_KANGARU_MSVC_NO_AUTOCALL_MAP_CHECK private: template::value, int> = 0> static std::true_type test(...); template::value, int> = 0> static std::false_type test(...); template static std::false_type test_helper(...); template class Map, typename U, typename C, std::size_t... S, int_t< service_map_t>>...> = 0> static std::true_type test_helper(seq); template static decltype(test_helper(tuple_seq>{})) test(int); public: using type = decltype(test(0)); #else using type = std::true_type; #endif }; template using is_autocall_entry_map_complete = typename is_autocall_entry_map_complete_helper::type; template struct is_autocall_entry_valid_helper { private: // This is workaround for clang. Clang will not interpret the name of the class itself // as a valid template template parameter. using this alias, it forces it to use the name as a template. template using self_t = typename is_autocall_entry_valid_helper::type; struct invoke_method_condition { template using type = std::integral_constant>>::value && dependency_check>>::value>; }; struct invoke_call_condition { template using type = is_invoke_call; }; template struct expander { using type = typename std::conditional::value, invoke_method_condition, invoke_call_condition>::type::template type::type; }; template static std::false_type test(...); template static std::false_type test_helper(...); template::type::value>...> = 0> static std::true_type test_helper(seq); template::value, int> = 0> static decltype(test_helper(tuple_seq>{})) test(int); public: using type = decltype(test(0)); }; template using is_autocall_entry_valid = typename is_autocall_entry_valid_helper::type; template using is_autocall_valid = autocall_trait; template struct is_service_valid : std::integral_constant::value && service_check::value && dependency_check::value && is_autocall_valid::value && dependency_trait::value > {}; template class Map, typename T, typename... Args> struct is_invoke_service_valid_helper { private: template struct expander { using type = std::integral_constant>>::value>; }; template using map_t = service_map_t; template>..., enable_if_t::type::value>...> = 0> static std::true_type test_helper(seq); template static std::false_type test_helper(...); template static decltype(test_helper(tuple_seq_minus, sizeof...(Args)>{})) test(int); template static std::false_type test(...); public: using type = decltype(test(0)); }; template class Map, typename T, typename... Args> struct is_invoke_service_valid : is_invoke_service_valid_helper::type {}; template class Map, typename T, typename... Args> using is_invoke_valid = std::integral_constant::value && is_invokable::value >; } // namespace detail } // namespace kgr #endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_TRAITS_HPP