/******************************************************************************* * boost/type_traits/detail/common_type_imp.hpp * * Copyright 2010, Jeffrey Hellrung. * 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) * * struct boost::common_type * * common_type::type is the type of the expression * b() ? x() : y() * where b() returns a bool, x() has return type T, and y() has return type U. * See * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#common_type * * Note that this evaluates to void if one or both of T and U is void. ******************************************************************************/ #ifndef BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP #define BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_IMP_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace detail_type_traits_common_type { /******************************************************************************* * struct propagate_cv< From, To > * * This metafunction propagates cv-qualifiers on type From to type To. ******************************************************************************/ template< class From, class To > struct propagate_cv { typedef To type; }; template< class From, class To > struct propagate_cv< const From, To > { typedef To const type; }; template< class From, class To > struct propagate_cv< volatile From, To > { typedef To volatile type; }; template< class From, class To > struct propagate_cv< const volatile From, To > { typedef To const volatile type; }; /******************************************************************************* * struct is_integral_or_enum * * This metafunction determines if T is an integral type which can be made * signed or unsigned. ******************************************************************************/ template< class T > struct is_integral_or_enum : mpl::or_< is_integral, is_enum > { }; template<> struct is_integral_or_enum< bool > : false_type { }; /******************************************************************************* * struct make_unsigned_soft * struct make_signed_soft * * These metafunction are identical to make_unsigned and make_signed, * respetively, except for special-casing bool. ******************************************************************************/ template< class T > struct make_unsigned_soft : make_unsigned { }; template<> struct make_unsigned_soft< bool > { typedef bool type; }; template< class T > struct make_signed_soft : make_signed { }; template<> struct make_signed_soft< bool > { typedef bool type; }; /******************************************************************************* * struct sizeof_t * typedef ... yes_type * typedef ... no_type * * These types are integral players in the use of the "sizeof trick", i.e., we * can distinguish overload selection by inspecting the size of the return type * of the overload. ******************************************************************************/ template< std::size_t N > struct sizeof_t { char _dummy[N]; }; typedef sizeof_t<1> yes_type; typedef sizeof_t<2> no_type; BOOST_MPL_ASSERT_RELATION( sizeof( yes_type ), ==, 1 ); BOOST_MPL_ASSERT_RELATION( sizeof( no_type ), ==, 2 ); /******************************************************************************* * rvalue_test(T&) -> no_type * rvalue_test(...) -> yes_type * * These overloads are used to determine the rvalue-ness of an expression. ******************************************************************************/ template< class T > no_type rvalue_test(T&); yes_type rvalue_test(...); /******************************************************************************* * struct conversion_test_overloads< Sequence > * * This struct has multiple overloads of the static member function apply, each * one taking a single parameter of a type within the Boost.MPL sequence * Sequence. Each such apply overload has a return type with sizeof equal to * one plus the index of the parameter type within Sequence. Thus, we can * deduce the type T of an expression as long as we can generate a finite set of * candidate types containing T via these apply overloads and the "sizeof * trick". ******************************************************************************/ template< class First, class Last, std::size_t Index > struct conversion_test_overloads_iterate : conversion_test_overloads_iterate< typename mpl::next< First >::type, Last, Index + 1 > { using conversion_test_overloads_iterate< typename mpl::next< First >::type, Last, Index + 1 >::apply; static sizeof_t< Index + 1 > apply(typename mpl::deref< First >::type); }; template< class Last, std::size_t Index > struct conversion_test_overloads_iterate< Last, Last, Index > { static sizeof_t< Index + 1 > apply(...); }; template< class Sequence > struct conversion_test_overloads : conversion_test_overloads_iterate< typename mpl::begin< Sequence >::type, typename mpl::end< Sequence >::type, 0 > { }; /******************************************************************************* * struct select< Sequence, Index > * * select is synonymous with mpl::at_c unless Index equals the size of the * Boost.MPL Sequence, in which case this evaluates to void. ******************************************************************************/ template< class Sequence, int Index, int N = mpl::size< Sequence >::value > struct select : mpl::at_c< Sequence, Index > { }; template< class Sequence, int N > struct select< Sequence, N, N > { typedef void type; }; /******************************************************************************* * class deduce_common_type< T, U, NominalCandidates > * struct nominal_candidates * struct common_type_dispatch_on_rvalueness * struct common_type_impl * * These classes and structs implement the logic behind common_type, which goes * roughly as follows. Let C be the type of the conditional expression * declval< bool >() ? declval() : declval() * if C is an rvalue, then: * let T' and U' be T and U stripped of reference- and cv-qualifiers * if T' and U' are pointer types, say, T' = V* and U' = W*, then: * define the set of NominalCandidates to be * { V*, W*, V'*, W'* } * where V' is V with whatever cv-qualifiers are on W, and W' is W * with whatever cv-qualifiers are on V * else if T' and U' are both integral or enum types, then: * define the set of NominalCandidates to be * { * unsigned_soft(T'), * unsigned_soft(U'), * signed_soft(T'), * signed_soft(U'), * T', * U', * unsigned int, * int * } * where unsigned_soft(X) is make_unsigned_soft::type and * signed_soft(X) is make_signed_soft::type (these are all * generally necessary to cover the various integral promotion cases) * else * define the set of NominalCandidates to be * { T', U' } * else * let V and W be T and U stripped of reference-qualifiers * define the set of NominalCandidates to be * { V&, W&, V'&, W'& } * where V' is V with whatever cv-qualifiers are on W, and W' is W with * whatever cv-qualifiers are on V * define the set of Candidates to be equal to the set of NominalCandidates with * duplicates removed, and use this set of Candidates to determine C using the * conversion_test_overloads struct ******************************************************************************/ template< class T, class U, class NominalCandidates > class deduce_common_type { typedef typename mpl::copy< NominalCandidates, mpl::inserter< mpl::vector0<>, mpl::if_< mpl::contains< mpl::_1, mpl::_2 >, mpl::_1, mpl::push_back< mpl::_1, mpl::_2 > > > >::type candidate_types; static const int best_candidate_index = sizeof( conversion_test_overloads< candidate_types >::apply( declval< bool >() ? declval() : declval() ) ) - 1; public: typedef typename select< candidate_types, best_candidate_index >::type type; }; template< class T, class U, class V = typename remove_cv< typename remove_reference::type >::type, class W = typename remove_cv< typename remove_reference::type >::type, bool = is_integral_or_enum::value && is_integral_or_enum::value > struct nominal_candidates { typedef mpl::vector2 type; }; template< class T, class U, class V, class W > struct nominal_candidates< T, U, V, W, true > { typedef boost::mpl::vector8< typename make_unsigned_soft::type, typename make_unsigned_soft::type, typename make_signed_soft::type, typename make_signed_soft::type, V, W, unsigned int, int > type; }; template< class T, class U, class V, class W > struct nominal_candidates< T, U, V*, W*, false > { typedef mpl::vector4< V*, W*, typename propagate_cv::type *, typename propagate_cv::type * > type; }; template struct common_type_dispatch_on_rvalueness : deduce_common_type< T, U, typename nominal_candidates::type > { }; template< class T, class U > struct common_type_dispatch_on_rvalueness< T, U, false > { private: typedef typename remove_reference::type unrefed_T_type; typedef typename remove_reference::type unrefed_U_type; public: typedef typename deduce_common_type< T, U, mpl::vector4< unrefed_T_type &, unrefed_U_type &, typename propagate_cv< unrefed_U_type, unrefed_T_type >::type &, typename propagate_cv< unrefed_T_type, unrefed_U_type >::type & > >::type type; }; template< class T, class U > struct common_type_impl : common_type_dispatch_on_rvalueness() ? declval() : declval() ) ) == sizeof( yes_type ) > { }; template< class T > struct common_type_impl< T, void > { typedef void type; }; template< class T > struct common_type_impl< void, T > { typedef void type; }; template<> struct common_type_impl< void, void > { typedef void type; }; #if 0 template< > struct common_type_impl< char, short> { typedef int type; }; template< > struct common_type_impl< short, char> { typedef int type; }; template< > struct common_type_impl< unsigned char, short> { typedef int type; }; template< > struct common_type_impl< short, unsigned char> { typedef int type; }; template< > struct common_type_impl< unsigned char, unsigned short> { typedef int type; }; template< > struct common_type_impl< unsigned short, unsigned char> { typedef int type; }; template< > struct common_type_impl< char, unsigned short> { typedef int type; }; template< > struct common_type_impl< unsigned short, char> { typedef int type; }; #endif } // namespace detail_type_traits_common_type } // namespace boost #endif // BOOST_TYPE_TRAITS_DETAIL_COMMON_TYPE_HPP