Select-By-Size |
|
The header <boost/utility/select_by_size.hpp> provides template classes and macros for determining the results of overload resolution at compile time using sizeof. It is intended as an alternative to type_traits::yes_type and type_traits::no_type from the Type Traits library. It provides an arbitrary number of types, case_<0>, case_<1>, case_<2>, ... , for use as the return types of helper functions, plus a template select_by_size which provides access to the result of the overload resolution. There is also a macro BOOST_SELECT_BY_SIZE, similar to BOOST_STATIC_CONSTANT, for use with compilers which have trouble with integral constant expressions. (See Coding Guidelines for Integral Constant Expressions.)
The typedefs yes_type and no_type are provided as shorthands for case_<1> and case_<0>. In some cases, case_<true> and case_<false> may be more suggestive. There is also a single return type representing a negative value: case_<-1>.
All types decribes in this document reside in the namespace boost::utility.
#include <boost/static_assert.hpp>
#define BOOST_SELECT_BY_SIZE_MAX_CASE 7
#include <boost/utility/select_by_size.hpp>
using namespace boost::utility;
case_<0> helper(bool);
case_<1> helper(int);
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("hello")) >::value;
BOOST_STATIC_ASSERT(value == 7);
};
struct test2 {
BOOST_SELECT_BY_SIZE(int, value, helper("hello"));
BOOST_STATIC_ASSERT(value == 7);
};
The defining property of the class template case_ is that the sizes of the types
case_<-1>, case_<0>, case_<1>, case_<2>, case_<3>, ...form a strictly increasing sequence. With well-behaved implementations, sizeof(case_<-1>) will be small, as will be the difference in size between adjacent types in the sequence.
The defining property of the class template select_by_size is that for each integer N in the range select_by_size through BOOST_SELECT_BY_SIZE_MAX_CASE, we have the equality
select_by_size< sizeof(case_<N>) >::value == N
The macro BOOST_SELECT_BY_SIZE(type, name, expr) can be used similarly to BOOST_STATIC_CONSTANT to define a static const intergral class member name of type type with value equal to select_by_size< sizeof(expr) >::value.
In order to make use of select_by_size with specializations case_<N> for N other than -1, 0 and 1, the symbol BOOST_SELECT_BY_SIZE_MAX_CASE must be defined as an intergral value greater than or equal to N before including the header <boost/utility/select_by_size.hpp>. The header may be included multiple times with different values of BOOST_SELECT_BY_SIZE_MAX_CASE.
It is possible to implement select_by_size in such a way that this macro is not necessary. See Implementation, below, for a discussion.
namespace boost {
namespace utility {
template<int N> struct case_ { [unspecified] };
template<unsigned N>
struct select_by_size {
struct type {
static const unsigned value =
[M such that sizeof(case_<M>) == N];
};
static const unsigned value = type::value;
};
#define BOOST_SELECT_BY_SIZE(type, name, expr) [unspecified]
}
}
Until recently the author knew of only one use for select_by_size with more than two cases, and so regarded it as a trick. He then discovered a second use, elevating it to a method. With the discovery of a third use, it is now a programming paradigm. (The three known uses are determing template arity, as in <boost/mpl/aux_/template_arity.hpp>, Joel de Guzman's type deduction system in the Boost Sandbox at <boost/utility/type_deduction.hpp>, and Reece Dunn's type deduction system for his Output Formatters library, also in the Boost Sandbox, at <boost/outfmt/detail/type_traits.hpp>. There are surely many more.)
select_by_size is implemented by explicit specialization for the values
sizeof(case_<-1>), sizeof(case_<0>), sizeof(case_<1>), sizeof(case_<2>), ... .As a result, there is a limit to the number of cases which can be used by default.
There are several ways to remove this restriction. For instance:
The present implementation was chosen to reduce dependencies on other libraries. If defining the macro BOOST_SELECT_BY_SIZE_MAX_CASE is considered too inconvenient, the default number of cases could be set to 10 or 20 with little noticeable overhead.
The program <libs/utility/select_by_size_test.cpp> has been tested successfully with the following compilers:
© Copyright Jonathan Turkanis 2004. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.