/************************************************************************************ * * * Copyright (c) 2014 - 2018 Axel Menzel * * * * This file is part of RTTR (Run Time Type Reflection) * * License: MIT License * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * * SOFTWARE. * * * *************************************************************************************/ #ifndef RTTR_DEFAULT_ARGUMENTS_H_ #define RTTR_DEFAULT_ARGUMENTS_H_ #include "rttr/detail/base/core_prerequisites.h" #include "rttr/detail/misc/misc_type_traits.h" #include "rttr/detail/misc/argument_extractor.h" #include "rttr/detail/misc/function_traits.h" #include namespace rttr { namespace detail { /*! * This class holds the data for the default arguments. */ template struct default_args { default_args() {} default_args(T&&... args) : m_args(std::forward(args)...) {} std::tuple m_args; }; template<> struct default_args<> { default_args() {} std::tuple<> m_args; }; struct constructor_type {}; struct function_type {}; ///////////////////////////////////////////////////////////////////////////////////////// // a helper class to store two default list, the user provided, with std::nullptr_t // and the function signature: // e.g. default_args , default_args // this is needed for the get_default_args() function, to copy the values from the std::nullptr_t list // to the function signature list template struct default_list { using default_types_func = T1; using default_types_provided = T2; }; // short cut for an empty list using empty_defaults = default_list, default_args<>>; ///////////////////////////////////////////////////////////////////////////////////////// // This type trait will check whether a signature (given via \p Arg_list) match the \o Default_Arg_List types. // It will check the signature recursively, beginning with the complete signature, // then removing the first argument and check against Default_Arg_List, then removing the second... template struct find_default_args_impl; template struct find_default_args_impl, Default_Arg_List> { template using decay_type = remove_cv_t>; using func_args = default_args< decay_type< T>, decay_type< TArgs>... >; using type = conditional_t< is_same_nullptr::value, default_list, typename find_default_args_impl, Default_Arg_List >::type >; }; template struct find_default_args_impl, Default_Arg_List> { using type = default_list, default_args<>>; }; ///////////////////////////////////////////////////////////////////////////////////////// /*! * This helper struct is needed to call `find_default_args_t` with a function signature, * or a constructor signature (a list of arguments), i.e. I have only one interface to invoke. * * This avoid code distinction in `has_default_types`or `get_default_args`. */ template struct find_default_args_helper; // is function template struct find_default_args_helper, Acc_Type, enable_if_t< std::is_same::value >> : find_default_args_impl< as_type_list_t< typename function_traits::arg_types >, Default_Arg_List> { }; // is ctor with one argument template struct find_default_args_helper, constructor_type, enable_if_t< is_one_argument::value >> : find_default_args_impl, Default_Arg_List> { }; // is ctor with zero or more then one argument template struct find_default_args_helper, constructor_type, enable_if_t< !is_one_argument::value >> : find_default_args_impl, Default_Arg_List> { }; /*! * This type traits will check whether it is possible to call * a function type or a list of argument types (e.g. constructor arguments) * depending on a list of default argument types, \p Default_Arg_List. * When it is possible \p Default_Arg_List will be returned as type; * Otherwise an empty 'default_args<>' will be returned * * e.g.: * ctor_list => ; Default_Arg_List => default_args will return: default_args * ctor_list => ; Default_Arg_List => default_args will return: default_args * ctor_list => ; Default_Arg_List => default_args will return: default_args * ctor_list => ; Default_Arg_List => default_args will return: default_args<> (cannot be called; right most argument is missing) */ template using find_default_args_t = typename find_default_args_helper::type; ///////////////////////////////////////////////////////////////////////////////////////// template struct is_def_type : std::false_type { }; template struct is_def_type > : std::true_type { }; ///////////////////////////////////////////////////////////////////////////////////////// template struct get_default_args_impl; template struct get_default_args_impl> { using type = conditional_t< is_def_type::value, T, typename get_default_args_impl>::type >; }; template<> struct get_default_args_impl> { using type = default_args<>; }; //! This type trait will return the first type which matches the template type `default_args` template using get_default_args_t = typename get_default_args_impl< type_list< TArgs... > >::type; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// /*! * Evaluates to 'std::true_type' when the given arguments contains one 'def_args' argument; * Otherwise to 'std::false_type' */ template using has_default_args = std::integral_constant, default_args<>>::value>; template struct has_default_types; /*! * Evaluates to 'std::true_type' when the given arguments contains one valid 'def_args' argument, * that can be used to invoke the signature \p Acc_Args; * Otherwise to 'std::false_type' */ template struct has_default_types, Acc_Type> : std::integral_constant, Acc_Args, Acc_Type>, empty_defaults>::value> { }; ///////////////////////////////////////////////////////////////////////////////////////// template using default_types_t = find_default_args_t, Acc_Args, Acc_Type>; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // returns the number of types 'default_args' provided in the given list of arguments TArgs... template using count_default_args = count_if... >; ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// template, Acc_Args, Acc_Type> > static RTTR_INLINE enable_if_t< std::is_same::value, typename Default_Type::default_types_func> get_default_args(Args&&... arg) { return default_args<>(); // no default arguments provided } ///////////////////////////////////////////////////////////////////////////////////////// template, Acc_Args, Acc_Type> > static RTTR_INLINE enable_if_t< !std::is_same::value, typename Default_Type::default_types_func> get_default_args(Args&&... arg) { // default arguments are provided, extract them auto result = forward_to_array(std::forward(arg)...); // because we knew there is exactly one detail::default_argument, // we can extract it without worry to check typename Default_Type::default_types_func ret; ret.m_args = std::move(result[0].m_args); return ret; } ///////////////////////////////////////////////////////////////////////////////////////// } // end namespace detail } // end namespace rttr #endif // RTTR_DEFAULT_ARGUMENTS_H_