Files
utility/select_by_size.html
Jonathan Turkanis 9063a9706c added more detailed discussion
[SVN r2017]
2004-03-04 01:35:26 +00:00

232 lines
13 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<STYLE>
.code { font-family:monospace; font-size: 10pt }
H1, H2, H3 { font-family:Verdana, Tahoma, sans-serif; font-weight:0 }
H1 { font-size: 20pt }
H2 { font-size: 16pt }
P { color: black }
TH { text-align:left }
A { text-decoration:none }
A:visited { color: #005E20 }
A.contact { color: black; text-decoration:none }
.code { font-family:monospace; font-size: 10pt }
.headingCode { font-family:monospace; font-size: 12pt }
.concept { font-weight: bold }
</STYLE>
</HEAD>
<BODY>
<TABLE BORDER='0' WIDTH='100%'>
<TR>
<TD WIDTH="*" STYLE='text-align:left'><H1>Select-By-Size</H1></TD>
<TD ALIGN=right>
<TABLE>
<TR>
<TD STYLE='text-align:center'><A HREF='../../index.html'><IMG BORDER=0 SRC='../../kangaroo.gif'></A></TD>
</TR>
<TR>
<TD ALIGN='center'>
<A STYLE='text-align:center;color: black;font: bold italic 12pt/17pt Verdana, sans-serif; text-decoration:none' HREF='../../index.html'>Metaprogramming<BR>Utilities</A>
</TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE>
<H2>Contents</H2>
<DL STYLE='margin-left:1em'>
<DT>1. <A HREF='#overview'>Overview</A>
<DT>2. <A HREF='#example'>Example</A>
<DT>3. <A HREF='#description'>Description</A>
<DT>4. <A HREF='#synopsis'>Synopsis</A>
<DT>5. <A HREF='#rationale'>Rationale</A>
<DT>6. <A HREF='#implementation'>Implementation</A>
<DT>7. <A HREF='#dependencies'>Dependencies</A>
<DT>8. <A HREF='#portability'>Portability</A>
<DT>9. <A HREF='#feedback'>Feedback</A>
</DL>
<A NAME='overview'></A>
<H2>Overview</H2>
<P>
The header <A HREF='../../boost/utility/select_by_size.hpp'><SPAN CLASS='code'>&lt;boost/utility/select_by_size.hpp&gt;</SPAN></A> provides template classes and macros for determining the results of overload resolution at compile time using <SPAN CLASS='code'>sizeof</SPAN>. It is intended as an alternative to <A HREF='http://www.boost.org/boost/type_traits/detail/yes_no_type.hpp'><SPAN CLASS='code'>type_traits::yes_type</SPAN></A> and <A HREF='http://www.boost.org/boost/type_traits/detail/yes_no_type.hpp'><SPAN CLASS='code'>type_traits::no_type</SPAN></A> from the <A HREF='http://www.boost.org/libs/type_traits/index.html'>Type Traits</A> library. It provides an arbitrary number of types, <SPAN CLASS='code'>case_&lt;0&gt;</SPAN>, <SPAN CLASS='code'>case_&lt;1&gt;</SPAN>, <SPAN CLASS='code'>case_&lt;2&gt;</SPAN>, <SPAN CLASS='code'>... </SPAN>, for use as the return types of helper functions, plus a template <SPAN CLASS='code'>select_by_size</SPAN> which provides access to the result of the overload resolution. There is also a macro <SPAN CLASS='code'>BOOST_SELECT_BY_SIZE</SPAN>, similar to <A HREF='http://www.boost.org/libs/config/config.htm'><SPAN CLASS='code'>BOOST_STATIC_CONSTANT</SPAN></A>, for use with compilers which have trouble with integral constant expressions. (<I>See</I> <A HREF='http://www.boost.org/more/int_const_guidelines.htm'>Coding Guidelines for Integral Constant Expressions</A>.)
</P>
<P>
The <SPAN CLASS='code'>typedefs</SPAN> <SPAN CLASS='code'>yes_type</SPAN> and <SPAN CLASS='code'>no_type</SPAN> are provided as shorthands for <SPAN CLASS='code'>case_&lt;1&gt;</SPAN> and <SPAN CLASS='code'>case_&lt;0&gt;</SPAN>. In some cases, <SPAN CLASS='code'>case_&lt;true&gt;</SPAN> and <SPAN CLASS='code'>case_&lt;false&gt;</SPAN> may be more suggestive. There is also a single return type representing a negative value: <SPAN CLASS='code'>case_&lt;-1&gt;</SPAN>.
</P>
<P>All types decribes in this document reside in the namespace <SPAN CLASS='code'>boost::utility</SPAN>.
<A NAME='example'></A>
<H2>Example</H2>
<PRE> #include &lt;boost/static_assert.hpp&gt;
#define BOOST_SELECT_BY_SIZE_MAX_CASE 7
#include &lt;boost/utility/select_by_size.hpp&gt;
using namespace boost::utility;
case_&lt;0&gt; helper(bool);
case_&lt;1&gt; helper(int);
case_&lt;2&gt; helper(unsigned);
case_&lt;3&gt; helper(long);
case_&lt;4&gt; helper(unsigned long);
case_&lt;5&gt; helper(float);
case_&lt;6&gt; helper(double);
case_&lt;7&gt; helper(const char*);
struct test {
static const int value =
select_by_size&lt; sizeof(helper("hello")) &gt;::value;
BOOST_STATIC_ASSERT(value == 7);
};
struct test2 {
BOOST_SELECT_BY_SIZE(int, value, helper("hello"));
BOOST_STATIC_ASSERT(value == 7);
};</PRE>
<A NAME='description'></A>
<H2>Description</H2>
<H3>The template <SPAN CLASS='headingCode'>case_</SPAN></H3>
<P>
The defining property of the class template <SPAN CLASS='code'>case_</SPAN> is that the sizes of the types
<PRE> case_&lt;-1&gt;, case_&lt;0&gt;, case_&lt;1&gt;, case_&lt;2&gt;, case_&lt;3&gt;, ...</PRE>
form a strictly increasing sequence. With well-behaved implementations, <SPAN CLASS='code'>sizeof(case_&lt;-1&gt;)</SPAN> will be small, as will be the difference in size between adjacent types in the sequence.
</P>
<H3>The template <SPAN CLASS='headingCode'>select_by_size</SPAN></H3>
<P>
The defining property of the class template <SPAN CLASS='code'>select_by_size</SPAN> is that for each integer <SPAN CLASS='code'>N</SPAN> in the range <SPAN CLASS='code'>select_by_size</SPAN> through <SPAN CLASS='code'>BOOST_SELECT_BY_SIZE_MAX_CASE</SPAN>, we have the equality
<PRE> select_by_size< sizeof(case_&lt;N&gt;) >::value == N</PRE>
</P>
<H3>The macro <SPAN CLASS='headingCode'>BOOST_SELECT_BY_SIZE</SPAN></H3>
<P>
The macro <SPAN CLASS='code'>BOOST_SELECT_BY_SIZE(type, name, expr)</SPAN> can be used similarly to <SPAN CLASS='code'>BOOST_STATIC_CONSTANT</SPAN> to define a <SPAN CLASS='code'>static const</SPAN> intergral class member <SPAN CLASS='code'>name</SPAN> of type <SPAN CLASS='code'>type</SPAN> with value equal to <SPAN CLASS='code'>select_by_size< sizeof(expr) >::value</SPAN>.
</P>
<H3>The macro <SPAN CLASS='headingCode'>BOOST_SELECT_BY_SIZE_MAX_CASE</SPAN></H3>
<P>
In order to make use of <SPAN CLASS='code'>select_by_size</SPAN> with specializations <SPAN CLASS='code'>case_&lt;N&gt;</SPAN> for <SPAN CLASS='code'>N</SPAN> other than <SPAN CLASS='code'>-1</SPAN>, <SPAN CLASS='code'>0</SPAN> and <SPAN CLASS='code'>1</SPAN>,
the symbol <SPAN CLASS='code'>BOOST_SELECT_BY_SIZE_MAX_CASE</SPAN> must be defined as an intergral value greater than or equal to <SPAN CLASS='code'>N</SPAN> before including the header <SPAN CLASS='code'>&lt;boost/utility/select_by_size.hpp&gt;</SPAN>. The header may be included multiple times with different values of <SPAN CLASS='code'>BOOST_SELECT_BY_SIZE_MAX_CASE</SPAN>.
</P>
<P>
It is possible to implement <SPAN CLASS='code'>select_by_size</SPAN> in such a way that this macro is not necessary. <I>See</I> <A HREF='#implementation'>Implementation</A>, below, for a discussion.
</P>
<A NAME='Synopsis'></A>
<H2>Synopsis</H2>
<PRE> namespace boost {
namespace utility {
template&lt;int N&gt; struct <B>case_</B> { [<I>unspecified</I>] };
template&lt;unsigned N&gt;
struct <B>select_by_size</B> {
struct type {
static const unsigned value =
[M <I>such that</I> sizeof(case_&lt;M&gt;) == N];
};
static const unsigned value = type::value;
};
#define <B>BOOST_SELECT_BY_SIZE</B>(type, name, expr) [<I>unspecified</I>]
}
}</PRE>
<A NAME='rationale'></A>
<H2>Rationale</H2>
The utility of <SPAN CLASS='code'>type_traits::yes_type</SPAN> and <SPAN CLASS='code'>type_traits::no_type</SPAN> is well-known. The advantages of using <SPAN CLASS='code'>select_by_size</SPAN> are:
<UL type='box'>
<LI STYLE='list-style-type: square'>It documents the fact that <SPAN CLASS='code'>sizeof</SPAN> is being used to determine the result of overload resolution.
<LI STYLE='list-style-type: square'>It eliminates the need to compare a given <SPAN CLASS='code'>sizeof</SPAN> expression with <SPAN CLASS='code'>sizeof(type_traits::yes_type)</SPAN>.
<LI STYLE='list-style-type: square'>It allows the use of an aribtrary number of cases.</LI>
</UL>
<P>
Until recently the author knew of only one use for <SPAN CLASS='code'>select_by_size</SPAN> with more than two cases, and so regarded it as a <I>trick</I>. He then discovered a second use, elevating it to a <I>method</I>. With the discovery of a third use, it is now a <I>programming paradigm</I>. (The three known uses are determing template arity, as in <A HREF='http://www.boost.org/boost/mpl/aux_/template_arity.hpp'><SPAN CLASS='code'>&lt;boost/mpl/aux_/template_arity.hpp&gt;</SPAN></A>, <A HREF='http://www.boost.org/people/joel_de_guzman.htm'>Joel de Guzman</A>'s type deduction system in the <A HREF='http://www.boost.org/more/mailing_lists.htm#sandbox'>Boost Sandbox</A> at <SPAN CLASS='code'>&lt;boost/utility/type_deduction.hpp&gt;</SPAN>, and Reece Dunn's type deduction system for his Output Formatters library, also in the <A HREF='http://www.boost.org/more/mailing_lists.htm#sandbox'>Boost Sandbox</A>, at <SPAN CLASS='code'>&lt;boost/outfmt/detail/type_traits.hpp&gt;</SPAN>. There are surely many more.)
</P>
<A NAME='implementation'></A>
<H2>Implementation</H2>
<P>
<SPAN CLASS='code'>select_by_size</SPAN> is implemented by explicit specialization for the values
<PRE> sizeof(case_&lt;-1&gt;), sizeof(case_&lt;0&gt;), sizeof(case_&lt;1&gt;), sizeof(case_&lt;2&gt;), ... .</PRE>
As a result, there is a limit to the number of cases which can be used by default.
</P>
<P>
There are several ways to remove this restriction. For instance:
<UL>
<LI STYLE='list-style-type: square'><SPAN CLASS='code'>select_by_size</SPAN> could be implemented to
iterate through the sequence <SPAN CLASS='code'>case_&lt;-1&gt;, case_&lt;0&gt;, case_&lt;1&gt;, ... </SPAN> until it finds
a specialization whose size is equal to its template argument, or
<LI STYLE='list-style-type: square'>The template <SPAN CLASS='code'>case_</SPAN> could be designed so
that its size is easy to compute, taking alignment issues into account.
</UL>
This first approach is computationally too expensive for a widely used utility. The second approach is feasable; a sample implementation using <A HREF='http://www.boost.org/boost/type_traits/alignment_of.hpp'><SPAN CLASS='code'>alignment_of</SPAN></A> and <A HREF='http://www.boost.org/boost/type_traits/type_with_alignment.hpp'><SPAN CLASS='code'>max_align</SPAN></A> from the <A HREF='http://www.boost.org/libs/config/config.htm'>Type Traits</A> library is given in the <A HREF='../../boost/utility/select_by_size.hpp'>source code</A>.
</P>
<P>
The present implementation was chosen to
reduce dependencies on other libraries. If defining the macro <SPAN CLASS='code'>BOOST_SELECT_BY_SIZE_MAX_CASE</SPAN> is considered too inconvenient, the default number of cases could be set to <SPAN CLASS='code'>10</SPAN> or <SPAN CLASS='code'>20</SPAN> with little noticeable overhead.
</P>
<A NAME='dependencies'></A>
<H2>Dependencies</H2>
The header <A HREF='../../boost/utility/select_by_size.hpp'><SPAN CLASS='code'>&lt;boost/utility/select_by_size.hpp&gt;</SPAN></A> depends on <A HREF='http://www.boost.org/libs/config/config.htm'>Boost.Config</A> and the <A HREF='http://www.boost.org/libs/preprocessor/doc/index.html'>Boost Preprocessor Library</A>.
<A NAME='portability'></A>
<H2>Portability</H2>
<P>
The program <A HREF='select_by_size_test.cpp'><SPAN CLASS='code'>&lt;libs/utility/select_by_size_test.cpp&gt;</SPAN></A> has been tested successfully with the following compilers:
<UL>
<LI STYLE='list-style-type: square'>Microsoft Visual C++ 6.0, SP 5</LI>
<LI STYLE='list-style-type: square'>Microsoft Visual C++ 7.1</LI>
<LI STYLE='list-style-type: square'>Metrowerks CodeWarrior 8.0</LI>
<LI STYLE='list-style-type: square'>Intel C++ Compiler for Windows 7.1 and 8.0</LI>
<LI STYLE='list-style-type: square'>GCC 2.95.3-10 (cygwin special)</LI>
<LI STYLE='list-style-type: square'>GCC 3.2 (MinGW)</LI>
<LI STYLE='list-style-type: square'>GCC 3.3.1 (cygming special)</LI>
<LI STYLE='list-style-type: square'>Comeau C/C++ 4.3.3</LI>
<LI STYLE='list-style-type: square'>Borland C++ 5.5.1 and 5.6.4</LI>
<LI STYLE='list-style-type: square'>DigitalMars 8.38n</LI>
</UL>
It should work on any recent compiler for which Boost has been configured.
</P>
<A NAME='feedback'></A>
<H2>Feedback</H2>
The author, Jonathan Turkanis, can be contacted at <A CLASS='contact' HREF='mailto:turkanis@kangaroologic.com'>turkanis@kangaroologic.com</A>
<HR STYLE='margin:20,0,0'>
<P STYLE='font-size:8pt'>
&copy; 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.
</P>
</BODY>