added more detailed discussion

[SVN r2017]
This commit is contained in:
Jonathan Turkanis
2004-03-04 01:35:26 +00:00
parent f2c6519460
commit 9063a9706c

View File

@@ -3,8 +3,10 @@
<HEAD>
<STYLE>
.code { font-family:monospace; font-size: 10pt }
H1 {text-align:center }
P { color: black; font-size: 10p }
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 }
@@ -17,72 +19,53 @@
<BODY>
<H1>Select By Size</H1>
<P STYLE='margin-left:30px'>
<TABLE>
<COLS WIDTH='*,10,*'>
<TR><TH>Author:</TH><TD></TD><TD>Jonathan Turkanis</TD></TR>
<TR><TH>Contact:</TH><TD></TD><TD><A CLASS='contact' HREF='mailto:turkanis@kangaroologic.com'>turkanis@kangaroologic.com</A></TD></TR>
<TR><TH>Date:</TH><TD></TD><TD>2004-02-11</TD></TR>
<TR><TH>Copyright:</TH><TD></TD><TD>Copyright Jonathan Turkanis 2004. All rights reserved</TD></TR>
<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>
</P>
<H2>Contents</H2>
<DL STYLE='margin-left:1em'>
<DT>1. <A HREF='#overview'>Overview</A>
<DT>2. <A HREF='#usage'>Usage</A>
<DT>3. <A HREF='#rationale'>Rationale</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='#dependencies'>Dependencies</A>
<DT>6. <A HREF='#portability'>Portability</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 CLAS='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>.) For convenience, a single return type representing a negative value is also provided: <SPAN CLASS='code'>case_&lt;-1&gt;</SPAN>.
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>.
<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>
<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>. Naturally, <SPAN CLASS='code'>case_&lt;true&gt;</SPAN> and <SPAN CLASS='code'>case_&lt;false&gt;</SPAN> may also be used.
</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_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 CLAS='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>
<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>
<A NAME='usage'></A>
<H2>Usage</H2>
<A NAME='example'></A>
<H2>Example</H2>
<PRE> #include &lt;boost/static_assert.hpp&gt;
#define BOOST_SELECT_BY_SIZE_MAX_CASE 7
@@ -110,6 +93,62 @@ form a strictly increasing sequence. With well-behaved implementations, <SPAN CL
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>
@@ -122,47 +161,48 @@ The utility of <SPAN CLASS='code'>type_traits::yes_type</SPAN> and <SPAN CLASS='
</UL>
<P>
Until recently the author was aware of only one use for item (3). Thus he regarded the use of <SPAN CLASS='code'>select_by_size</SPAN> with more than two cases 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='../../boost/mpl/aux_/template_arity.hpp'><SPAN CLAS='code'>&lt;boost/mpl/aux_/template_arity.hpp&gt;</SPAN></A>, Joel de Guzman's type deduction system in the <A HREF='http://www.boost.org/more/mailing_lists.htm#sandbox'>Boost Sandbox</A> at <SPAN CLAS='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 CLAS='code'>&lt;boost/outfmt/detail/type_traits.hpp&gt;</SPAN>.
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='Synopsis'></A>
<H2>Synopsis</H2>
<PRE> namespace boost {
namespace utility {
template&lt;int N&gt; struct <B>case_</B>;
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>implementation-defined</I>]
}
}</PRE>
<A NAME='dependencies'></A>
<H2>Dependencies</H2>
The header <A HREF='../../boost/utility/select_by_size.hpp'><SPAN CLAS='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 <A HREF='http://www.boost.org/libs/preprocessor/doc/index.html'>Boost.Preprocessor</A>.
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 CLAS='code'>&lt;libs/utility/select_by_size_test.cpp&gt;</SPAN></A> has been tested successfully with the following compilers:
<UL type='box'>
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 CodeWariror 8.0</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>
@@ -171,8 +211,14 @@ The header <A HREF='../../boost/utility/select_by_size.hpp'><SPAN CLAS='code'>&l
<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'>