// // Copyright (C) 2010 Rutger ter Borg // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef IS_CALLABLE_HPP #define IS_CALLABLE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace detail { typedef char yes_type; typedef char (&no_type)[2]; struct dont_care { dont_care( ... ); }; struct private_type { private_type const &operator, (int) const; }; template no_type is_private_type( const T& ); yes_type is_private_type( const private_type& ); template< typename Function, int Arity > struct function_unwrap {}; template< typename Function, typename Parameters, int Arity > struct can_be_called_impl {}; #define GENERATE_TEXT( z, which, text ) text #define GENERATE_STATIC_ARG_REF( z, which, unused ) \ static typename boost::mpl::at_c< Parameters, which >::type &BOOST_PP_CAT( a, which ); #define GENERATE_CAN_BE_CALLED( z, which, unused ) \ \ template< typename Function > \ struct function_unwrap< Function, which >: Function { \ function_unwrap(); \ typedef const private_type &(*pointer_to_function)( \ BOOST_PP_ENUM( which, GENERATE_TEXT, dont_care ) \ ); \ operator pointer_to_function() const; \ }; \ \ \ template< typename Function, typename Parameters > \ struct can_be_called_impl< Function, Parameters, which > { \ \ static function_unwrap< Function, which > &fun; \ BOOST_PP_REPEAT( which, GENERATE_STATIC_ARG_REF, ~ ) \ \ static const bool value = ( \ sizeof(no_type) == sizeof( is_private_type( (fun( \ BOOST_PP_ENUM_PARAMS( which, a ) \ ), 0 ) ) ) \ ); \ \ typedef boost::mpl::bool_< value > type; \ }; BOOST_PP_REPEAT( 6, GENERATE_CAN_BE_CALLED, ~ ) template< typename Function, typename Parameters > struct can_be_called: can_be_called_impl< Function, Parameters, boost::mpl::size< Parameters >::value > {}; } // namespace detail //! //! Function: either a pointer to a function, a reference to a function, //! a pointer to a member function, or a function object. //! Parameters: a MPL Random Access Sequence of parameter types //! template< typename Function, typename Parameters, typename Enable = void > struct is_callable: boost::mpl::false_ {}; //! //! Function is a pointer to a function or a reference to a function: //! In this case we know the parameter list, so we can check if the supplied //! Parameters are convertible to those of the function. If they are, the function //! is callable. TODO/Caveat: if functions are passed as parameters, is_convertible //! is not the most reliable solution. //! template< typename Function, typename Parameters > struct is_callable< Function, Parameters, typename boost::enable_if< boost::mpl::or_< boost::is_function< typename boost::remove_pointer< Function >::type >, boost::is_function< typename boost::remove_reference< Function >::type > > >::type >: boost::mpl::equal< Parameters, boost::function_types::parameter_types< Function >, boost::is_convertible< boost::mpl::_1, boost::mpl::_2 > > {}; //! //! Function is a member function pointer: remove the first parameter (the pointer to the class) //! to get the "cleaned" up parameter list. //! template< typename Function, typename Parameters > struct is_callable< Function, Parameters, typename boost::enable_if< boost::is_member_function_pointer< Function > >::type >: boost::mpl::equal< Parameters, typename boost::mpl::pop_front< boost::function_types::parameter_types< Function > >::type, boost::is_convertible< boost::mpl::_1, boost::mpl::_2 > > {}; //! //! Function is a function object / class: use the trick documented at //! http://www.boost.org/doc/libs/1_42_0/doc/html/proto/appendices.html //! //! TODO: add tags for const-ness and other qualifiers. //! template< typename Function, typename Parameters > struct is_callable< Function, Parameters, typename boost::enable_if< boost::is_class< Function > >::type >: detail::can_be_called< Function, Parameters > {}; #endif