diff --git a/include/boost/utility/select_by_size.hpp b/include/boost/utility/select_by_size.hpp index d1d6482..4710b68 100644 --- a/include/boost/utility/select_by_size.hpp +++ b/include/boost/utility/select_by_size.hpp @@ -4,50 +4,107 @@ // software is provided "as is" without express or implied warranty, and // with no claim as to its suitability for any purpose. +// +// Intended as an alternative to type_traits::yes_type and type_traits::no_type. +// Provides an arbitrary number of types (case_<0>, case_<1>, ...) for +// determining the results of overload resultion using 'sizeof', plus a uniform +// means of using the result. yes_type and no_type are typedefs for case_<1> +// and case_<0>. +// +// This header may be included any number of times, with +// BOOST_SELECT_BY_SIZE_CASES defined to be the number of cases needed for a +// particular application. It defaults to 2. +// +// This header depends only on Boost.Config and Boost.Preprocessor. +// +// Example usage: +// +// #define BOOST_SELECT_BY_SIZE_CASES 8 // Needed for > 2 cases. +// #include +// +// using namespace boost::utility; +// +// case_<0> helper(bool); // could use 'case_' or 'no_type'. +// case_<1> helper(int); // could use 'case_' or' yes_type'. +// case_<2> helper(unsigned); +// case_<3> helper(long); +// case_<4> helper(unsigned long); +// case_<5> helper(float); +// case_<6> helper(double); +// case_<7> helper(const char*); +// +// struct test { +// static const int value = +// select_by_size< sizeof(helper(9876UL)) >::value; +// BOOST_STATIC_ASSERT(value == 4); +// }; +// +// For compilers with integral constant expression problems, e.g. Borland 5.x, +// one can also write +// +// struct test { +// BOOST_SELECT_BY_SIZE(int, value, helper(9876UL)); +// }; +// +// to define a static integral constant 'value' equal to +// +// select_by_size< sizeof(helper(9876UL)) >::value. +// + +// Include guards surround all contents of this header except for explicit +// specializations of select_by_size for case_ with N > 2. + #ifndef BOOST_UTILITY_SELECT_BY_SIZE_HPP_INCLUDED #define BOOST_UTILITY_SELECT_BY_SIZE_HPP_INCLUDED -#include // BOOST_STATIC_CONSTANT. -#include -#include -#include +// The lowest N for which select_by_size< sizeof(case_) > has not been +// specialized. +#define SELECT_BY_SIZE_MAX_SPECIALIZED 2 -#ifndef BOOST_SELECT_BY_SIZE_MAX_CASE -#define BOOST_SELECT_BY_SIZE_MAX_CASE 30 -#endif +#include // BOOST_STATIC_CONSTANT, BOOST_NESTED_TEMPLATE +#include +#include +#include namespace boost { namespace utility { //--------------Definition of case_-------------------------------------------// -template struct case_; -template<> struct case_<0> { char c; }; -template struct case_ { char c1; case_ c2; }; +template struct case_ { char c1; case_ c2; }; +template<> struct case_<-1> { char c; }; typedef case_ yes_type; typedef case_ no_type; -//--------------Definition of select_by_size----------------------------------// +//--------------Declaration of select_by_size---------------------------------// template struct select_by_size; -// Specialize select_by_size for values sizeof(case_<0>), sizeof(case_<1>), -// ..., sizeof(case_(BOOST_SELECT_BY_SIZE_MAX_CASE>). -#define SELECT_BY_SIZE_SPEC(z, n, text) \ - namespace detail { \ - static const int BOOST_PP_CAT(sizeof_case_, n) = sizeof(case_); \ - } \ - template<> \ - struct select_by_size< detail::BOOST_PP_CAT(sizeof_case_, n) > \ - : mpl::int_ { }; \ - /**/ -BOOST_PP_REPEAT(BOOST_SELECT_BY_SIZE_MAX_CASE, SELECT_BY_SIZE_SPEC, _); -#undef SELECT_BY_SIZE_SPEC - } } // End namespaces utility, boost. +//--------------Definition of SELECT_BY_SIZE_SPEC-----------------------------// + +// Sepecializes select_by_size for sizeof(case). The decrement is used +// here because -1 cannot be passed +#define SELECT_BY_SIZE_SPEC(n) \ + namespace boost { namespace utility { \ + namespace detail { \ + static const int BOOST_PP_CAT(sizeof_case_, n) = sizeof(case_); \ + } \ + template<> \ + struct select_by_size< detail::BOOST_PP_CAT(sizeof_case_, n) > { \ + BOOST_STATIC_CONSTANT(int, value = n - 1); \ + }; \ + } } \ + /**/ + +//--------------Default specializations of select_by_size---------------------// + +SELECT_BY_SIZE_SPEC(0) // select_by_size< sizeof(case<-1>) > +SELECT_BY_SIZE_SPEC(1) // select_by_size< sizeof(case<0>) > +SELECT_BY_SIZE_SPEC(2) // select_by_size< sizeof(case<1>) > + //--------------Definition of SELECT_BY_SIZE----------------------------------// -#define BOOST_SELECT_BY_SIZE_ASSIGN(lhs, rhs) lhs = rhs #define BOOST_SELECT_BY_SIZE(type_, name, expr) \ BOOST_STATIC_CONSTANT( \ unsigned, \ @@ -58,10 +115,35 @@ BOOST_PP_REPEAT(BOOST_SELECT_BY_SIZE_MAX_CASE, SELECT_BY_SIZE_SPEC, _); name = \ ( boost::utility::select_by_size< \ BOOST_PP_CAT(boost_select_by_size_temp_, name) \ - >::type::value ) \ + >::value ) \ ) \ /**/ -#undef BOOST_SELECT_BY_SIZE_MAX_CASE - #endif // #ifndef BOOST_UTILITY_SELECT_BY_SIZE_HPP_INCLUDED + +//----------Specializations of SELECT_BY_SIZE (outside main inclued guards)---// + +// Specialize select_by_size for sizeof(case_) for each N less than +// BOOST_SELECT_BY_SIZE_CASES for which this specialization has not already been +// performed. + +#if !BOOST_PP_IS_ITERATING //-------------------------------------------------// + #include + #if !defined(BOOST_SELECT_BY_SIZE_CASES) || (BOOST_SELECT_BY_SIZE_CASES < 2) + #undef BOOST_SELECT_BY_SIZE_CASES + #define BOOST_SELECT_BY_SIZE_CASES 2 + #endif + + #if (BOOST_SELECT_BY_SIZE_CASES > SELECT_BY_SIZE_MAX_SPECIALIZED) + #define BOOST_PP_FILENAME_1 + #define BOOST_PP_ITERATION_LIMITS ( SELECT_BY_SIZE_MAX_SPECIALIZED, \ + BOOST_SELECT_BY_SIZE_CASES ) + #include BOOST_PP_ITERATE() + #undef SELECT_BY_SIZE_MAX_SPECIALIZED + #define SELECT_BY_SIZE_MAX_SPECIALIZED BOOST_SELECT_BY_SIZE_CASES + #endif // #if (BOOST_SELECT_BY_SIZE_CASES > SELECT_BY_SIZE_MAX_SPECIALIZED) + + #undef BOOST_SELECT_BY_SIZE_CASES +#else // #if !BOOST_PP_IS_ITERATING //----------------------------------------// + SELECT_BY_SIZE_SPEC(BOOST_PP_INC(BOOST_PP_ITERATION())) +#endif // #if !BOOST_PP_IS_ITERATING //---------------------------------------//