Chris@16: // - lambda_traits.hpp --- Boost Lambda Library ---------------------------- Chris@16: // Chris@16: // Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // For more information, see www.boost.org Chris@16: // ------------------------------------------------------------------------- Chris@16: Chris@16: #ifndef BOOST_LAMBDA_LAMBDA_TRAITS_HPP Chris@16: #define BOOST_LAMBDA_LAMBDA_TRAITS_HPP Chris@16: Chris@16: #include "boost/type_traits/transform_traits.hpp" Chris@16: #include "boost/type_traits/cv_traits.hpp" Chris@16: #include "boost/type_traits/function_traits.hpp" Chris@16: #include "boost/type_traits/object_traits.hpp" Chris@16: #include "boost/tuple/tuple.hpp" Chris@16: Chris@16: namespace boost { Chris@16: namespace lambda { Chris@16: Chris@16: // -- if construct ------------------------------------------------ Chris@16: // Proposed by Krzysztof Czarnecki and Ulrich Eisenecker Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template struct IF { typedef Then RET; }; Chris@16: Chris@16: template struct IF { Chris@16: typedef Else RET; Chris@16: }; Chris@16: Chris@16: Chris@16: // An if construct that doesn't instantiate the non-matching template: Chris@16: Chris@16: // Called as: Chris@16: // IF_type::type Chris@16: // The matching template must define the typeded 'type' Chris@16: // I.e. A::type if condition is true, B::type if condition is false Chris@16: // Idea from Vesa Karvonen (from C&E as well I guess) Chris@16: template Chris@16: struct IF_type_ Chris@16: { Chris@16: typedef typename T::type type; Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct IF_type Chris@16: { Chris@16: typedef typename Chris@16: IF_type_::RET >::type type; Chris@16: }; Chris@16: Chris@16: // helper that can be used to give typedef T to some type Chris@16: template struct identity_mapping { typedef T type; }; Chris@16: Chris@16: // An if construct for finding an integral constant 'value' Chris@16: // Does not instantiate the non-matching branch Chris@16: // Called as IF_value::value Chris@16: // If condition is true A::value must be defined, otherwise B::value Chris@16: Chris@16: template Chris@16: struct IF_value_ Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, value = T::value); Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct IF_value Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(int, value = (IF_value_::RET>::value)); Chris@16: }; Chris@16: Chris@16: Chris@16: // -------------------------------------------------------------- Chris@16: Chris@16: // removes reference from other than function types: Chris@16: template class remove_reference_if_valid Chris@16: { Chris@16: Chris@16: typedef typename boost::remove_reference::type plainT; Chris@16: public: Chris@16: typedef typename IF< Chris@16: boost::is_function::value, Chris@16: T, Chris@16: plainT Chris@16: >::RET type; Chris@16: Chris@16: }; Chris@16: Chris@16: Chris@16: template struct remove_reference_and_cv { Chris@16: typedef typename boost::remove_cv< Chris@16: typename boost::remove_reference::type Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: // returns a reference to the element of tuple T Chris@16: template struct tuple_element_as_reference { Chris@16: typedef typename Chris@16: boost::tuples::access_traits< Chris@16: typename boost::tuples::element::type Chris@16: >::non_const_type type; Chris@16: }; Chris@16: Chris@16: // returns the cv and reverence stripped type of a tuple element Chris@16: template struct tuple_element_stripped { Chris@16: typedef typename Chris@16: remove_reference_and_cv< Chris@16: typename boost::tuples::element::type Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: // is_lambda_functor ------------------------------------------------- Chris@16: Chris@16: template struct is_lambda_functor_ { Chris@16: BOOST_STATIC_CONSTANT(bool, value = false); Chris@16: }; Chris@16: Chris@16: template struct is_lambda_functor_ > { Chris@16: BOOST_STATIC_CONSTANT(bool, value = true); Chris@16: }; Chris@16: Chris@16: } // end detail Chris@16: Chris@16: Chris@16: template struct is_lambda_functor { Chris@16: BOOST_STATIC_CONSTANT(bool, Chris@16: value = Chris@16: detail::is_lambda_functor_< Chris@16: typename detail::remove_reference_and_cv::type Chris@16: >::value); Chris@16: }; Chris@16: Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: // -- parameter_traits_ --------------------------------------------- Chris@16: Chris@16: // An internal parameter type traits class that respects Chris@16: // the reference_wrapper class. Chris@16: Chris@16: // The conversions performed are: Chris@16: // references -> compile_time_error Chris@16: // T1 -> T2, Chris@16: // reference_wrapper -> T& Chris@16: // const array -> ref to const array Chris@16: // array -> ref to array Chris@16: // function -> ref to function Chris@16: Chris@16: // ------------------------------------------------------------------------ Chris@16: Chris@16: template Chris@16: struct parameter_traits_ { Chris@16: typedef T2 type; Chris@16: }; Chris@16: Chris@16: // Do not instantiate with reference types Chris@16: template struct parameter_traits_ { Chris@16: typedef typename Chris@16: generate_error:: Chris@16: parameter_traits_class_instantiated_with_reference_type type; Chris@16: }; Chris@16: Chris@16: // Arrays can't be stored as plain types; convert them to references Chris@16: template struct parameter_traits_ { Chris@16: typedef T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_ { Chris@16: typedef const T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_ { Chris@16: typedef volatile T (&type)[n]; Chris@16: }; Chris@16: template Chris@16: struct parameter_traits_ { Chris@16: typedef const volatile T (&type)[n]; Chris@16: }; Chris@16: Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any >{ Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any >{ Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any >{ Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any >{ Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_ { Chris@16: typedef void type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: // Are the volatile versions needed? Chris@16: template Chris@16: struct parameter_traits_, Any > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parameter_traits_, Any > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: } // end namespace detail Chris@16: Chris@16: Chris@16: // ------------------------------------------------------------------------ Chris@16: // traits classes for lambda expressions (bind functions, operators ...) Chris@16: Chris@16: // must be instantiated with non-reference types Chris@16: Chris@16: // The default is const plain type ------------------------- Chris@16: // const T -> const T, Chris@16: // T -> const T, Chris@16: // references -> compile_time_error Chris@16: // reference_wrapper -> T& Chris@16: // array -> const ref array Chris@16: template Chris@16: struct const_copy_argument { Chris@16: typedef typename Chris@16: detail::parameter_traits_< Chris@16: T, Chris@16: typename detail::IF::value, T&, const T>::RET Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: // T may be a function type. Without the IF test, const would be added Chris@16: // to a function type, which is illegal. Chris@16: Chris@16: // all arrays are converted to const. Chris@16: // This traits template is used for 'const T&' parameter passing Chris@16: // and thus the knowledge of the potential Chris@16: // non-constness of an actual argument is lost. Chris@16: template struct const_copy_argument { Chris@16: typedef const T (&type)[n]; Chris@16: }; Chris@16: template struct const_copy_argument { Chris@16: typedef const volatile T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct const_copy_argument {}; Chris@16: // do not instantiate with references Chris@16: // typedef typename detail::generate_error::references_not_allowed type; Chris@16: Chris@16: Chris@16: template<> Chris@16: struct const_copy_argument { Chris@16: typedef void type; Chris@16: }; Chris@16: Chris@16: Chris@16: // Does the same as const_copy_argument, but passes references through as such Chris@16: template Chris@16: struct bound_argument_conversion { Chris@16: typedef typename const_copy_argument::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bound_argument_conversion { Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: // The default is non-const reference ------------------------- Chris@16: // const T -> const T&, Chris@16: // T -> T&, Chris@16: // references -> compile_time_error Chris@16: // reference_wrapper -> T& Chris@16: template Chris@16: struct reference_argument { Chris@16: typedef typename detail::parameter_traits_::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct reference_argument { Chris@16: typedef typename detail::generate_error::references_not_allowed type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct reference_argument > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct reference_argument > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: // Are the volatile versions needed? Chris@16: template Chris@16: struct reference_argument > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct reference_argument > { Chris@16: typedef lambda_functor type; Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct reference_argument { Chris@16: typedef void type; Chris@16: }; Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: // Array to pointer conversion Chris@16: template Chris@16: struct array_to_pointer { Chris@16: typedef T type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct array_to_pointer { Chris@16: typedef const T* type; Chris@16: }; Chris@16: template Chris@16: struct array_to_pointer { Chris@16: typedef T* type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct array_to_pointer { Chris@16: typedef const T* type; Chris@16: }; Chris@16: template Chris@16: struct array_to_pointer { Chris@16: typedef T* type; Chris@16: }; Chris@16: Chris@16: Chris@16: // --------------------------------------------------------------------------- Chris@16: // The call_traits for bind Chris@16: // Respects the reference_wrapper class. Chris@16: Chris@16: // These templates are used outside of bind functions as well. Chris@16: // the bind_tuple_mapper provides a shorter notation for default Chris@16: // bound argument storing semantics, if all arguments are treated Chris@16: // uniformly. Chris@16: Chris@16: // from template foo(const T& t) : bind_traits::type Chris@16: // from template foo(T& t) : bind_traits::type Chris@16: Chris@16: // Conversions: Chris@16: // T -> const T, Chris@16: // cv T -> cv T, Chris@16: // T& -> T& Chris@16: // reference_wrapper -> T& Chris@16: // const reference_wrapper -> T& Chris@16: // array -> const ref array Chris@16: Chris@16: // make bound arguments const, this is a deliberate design choice, the Chris@16: // purpose is to prevent side effects to bound arguments that are stored Chris@16: // as copies Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef const T type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: // null_types are an exception, we always want to store them as non const Chris@16: // so that other templates can assume that null_type is always without const Chris@16: template<> Chris@16: struct bind_traits { Chris@16: typedef null_type type; Chris@16: }; Chris@16: Chris@16: // the bind_tuple_mapper, bind_type_generators may Chris@16: // introduce const to null_type Chris@16: template<> Chris@16: struct bind_traits { Chris@16: typedef null_type type; Chris@16: }; Chris@16: Chris@16: // Arrays can't be stored as plain types; convert them to references. Chris@16: // All arrays are converted to const. This is because bind takes its Chris@16: // parameters as const T& and thus the knowledge of the potential Chris@16: // non-constness of actual argument is lost. Chris@16: template struct bind_traits { Chris@16: typedef const T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef const T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template struct bind_traits { Chris@16: typedef const volatile T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef const volatile T (&type)[n]; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3, Arg4); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits { Chris@16: typedef R(&type)(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits >{ Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct bind_traits >{ Chris@16: typedef T& type; Chris@16: }; Chris@16: Chris@16: template<> Chris@16: struct bind_traits { Chris@16: typedef void type; Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: template < Chris@16: class T0 = null_type, class T1 = null_type, class T2 = null_type, Chris@16: class T3 = null_type, class T4 = null_type, class T5 = null_type, Chris@16: class T6 = null_type, class T7 = null_type, class T8 = null_type, Chris@16: class T9 = null_type Chris@16: > Chris@16: struct bind_tuple_mapper { Chris@16: typedef Chris@16: tuple::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type, Chris@16: typename bind_traits::type> type; Chris@16: }; Chris@16: Chris@16: // bind_traits, except map const T& -> const T Chris@16: // this is needed e.g. in currying. Const reference arguments can Chris@16: // refer to temporaries, so it is not safe to store them as references. Chris@16: template struct remove_const_reference { Chris@16: typedef typename bind_traits::type type; Chris@16: }; Chris@16: Chris@16: template struct remove_const_reference { Chris@16: typedef const T type; Chris@16: }; Chris@16: Chris@16: Chris@16: // maps the bind argument types to the resulting lambda functor type Chris@16: template < Chris@16: class T0 = null_type, class T1 = null_type, class T2 = null_type, Chris@16: class T3 = null_type, class T4 = null_type, class T5 = null_type, Chris@16: class T6 = null_type, class T7 = null_type, class T8 = null_type, Chris@16: class T9 = null_type Chris@16: > Chris@16: class bind_type_generator { Chris@16: Chris@16: typedef typename Chris@16: detail::bind_tuple_mapper< Chris@16: T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 Chris@16: >::type args_t; Chris@16: Chris@16: BOOST_STATIC_CONSTANT(int, nof_elems = boost::tuples::length::value); Chris@16: Chris@16: typedef Chris@16: action< Chris@16: nof_elems, Chris@16: function_action Chris@16: > action_type; Chris@16: Chris@16: public: Chris@16: typedef Chris@16: lambda_functor< Chris@16: lambda_functor_base< Chris@16: action_type, Chris@16: args_t Chris@16: > Chris@16: > type; Chris@16: Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: } // detail Chris@16: Chris@16: template inline const T& make_const(const T& t) { return t; } Chris@16: Chris@16: Chris@16: } // end of namespace lambda Chris@16: } // end of namespace boost Chris@16: Chris@16: Chris@16: Chris@16: #endif // BOOST_LAMBDA_TRAITS_HPP