forked from boostorg/utility
This commit was manufactured by cvs2svn to create branch 'expaler'.
[SVN r2110]
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
project boost-sandbox/utility/doc ;
|
|
||||||
import boostbook ;
|
|
||||||
import doxygen ;
|
|
||||||
|
|
||||||
doxygen reference : ../../../boost/tribool.hpp : <prefix>boost ;
|
|
||||||
boostbook tribool : tribool.boostbook ;
|
|
@@ -1,417 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
|
||||||
<HTML>
|
|
||||||
<HEAD><TITLE>enable_if</TITLE>
|
|
||||||
|
|
||||||
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
||||||
<META name="GENERATOR" content="hevea 1.06">
|
|
||||||
</HEAD>
|
|
||||||
<BODY >
|
|
||||||
<!--HEVEA command line is: hevea -nosymb -noiso -pedantic -v enable_if_docs_for_boost.tex -->
|
|
||||||
<!--HTMLHEAD-->
|
|
||||||
<!--ENDHTML-->
|
|
||||||
<!--PREFIX <ARG ></ARG>-->
|
|
||||||
<!--CUT DEF section 1 -->
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<img border="0" src="c++boost.gif" align="center" width="277" height="86">enable_if</h1>
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC section Introduction-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc1">1</A> Introduction</H2><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="introduction"></A>
|
|
||||||
The <TT>enable_if</TT> family of templates is a set of tools to allow a function template or a class template specialization
|
|
||||||
to include or exclude itself from a set of matching functions or specializations
|
|
||||||
based on properties of its template arguments.
|
|
||||||
For example, one can define function templates that
|
|
||||||
are only enabled for, and thus only match, an arbitrary set of types
|
|
||||||
defined by a traits class. The <TT>enable_if</TT> templates can also be
|
|
||||||
applied to enable class template specializations. Applications of
|
|
||||||
<TT>enable_if</TT> are discussed in length
|
|
||||||
in [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>] and [<A HREF="#jarvi:03:c++typeclasses"><CITE>2</CITE></A>].<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Synopsis-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc2">1.1</A> Synopsis</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:synopsis"></A>
|
|
||||||
<PRE>
|
|
||||||
namespace boost {
|
|
||||||
template <class Cond, class T = void> struct enable_if;
|
|
||||||
template <class Cond, class T = void> struct disable_if;
|
|
||||||
template <class Cond, class T> struct lazy_enable_if;
|
|
||||||
template <class Cond, class T> struct lazy_disable_if;
|
|
||||||
|
|
||||||
template <bool B, class T = void> struct enable_if_c;
|
|
||||||
template <bool B, class T = void> struct disable_if_c;
|
|
||||||
template <bool B, class T> struct lazy_enable_if_c;
|
|
||||||
template <bool B, class T> struct lazy_disable_if_c;
|
|
||||||
}
|
|
||||||
</PRE>
|
|
||||||
<!--TOC subsection Background-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc3">1.2</A> Background</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:background"></A>
|
|
||||||
Sensible operation of template function overloading in C++ relies
|
|
||||||
on the <EM>SFINAE</EM> (substitution-failure-is-not-an-error)
|
|
||||||
principle [<A HREF="#vandevoorde2002:templates"><CITE>3</CITE></A>]: if an invalid argument
|
|
||||||
or return type is formed during the instantiation of a function
|
|
||||||
template, the instantiation is removed from the overload resolution
|
|
||||||
set instead of causing a compilation error. The following example,
|
|
||||||
taken from [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>],
|
|
||||||
demonstrates why this is important:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
int negate(int i) { return -i; }
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
typename F::result_type negate(const F& f) { return -f(); }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
Suppose the compiler encounters the call <TT>negate(1)</TT>. The first
|
|
||||||
definition is obviously a better match, but the compiler must
|
|
||||||
nevertheless consider (and instantiate the prototypes) of both
|
|
||||||
definitions to find this out. Instantiating the latter definition with
|
|
||||||
<TT>F</TT> as <TT>int</TT> would result in:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
int::result_type negate(const int&);
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
where the return type is invalid. If this was an error, adding an unrelated function template
|
|
||||||
(that was never called) could break otherwise valid code.
|
|
||||||
Due to the SFINAE principle the above example is not, however, erroneous.
|
|
||||||
The latter definition of <TT>negate</TT> is simply removed from the overload resolution set.<BR>
|
|
||||||
<BR>
|
|
||||||
The <TT>enable_if</TT> templates are tools for controlled creation of the SFINAE
|
|
||||||
conditions.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC section The <TT>enable_if</TT> templates-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc4">2</A> The <TT>enable_if</TT> templates</H2><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="enable_if"></A>
|
|
||||||
The names of the <TT>enable_if</TT> templates have three parts: an optional <TT>lazy_</TT> tag,
|
|
||||||
either <TT>enable_if</TT> or <TT>disable_if</TT>, and an optional <TT>_c</TT> tag.
|
|
||||||
All eight combinations of these parts are supported.
|
|
||||||
The meaning of the <TT>lazy_</TT> tag is described in Section <A HREF="#sec:enable_if_lazy">3.3</A>.
|
|
||||||
The second part of the name indicates whether a true condition argument should
|
|
||||||
enable or disable the current overload.
|
|
||||||
The third part of the name indicates whether the condition argument is a <TT>bool</TT> value
|
|
||||||
(<TT>_c</TT> suffix), or a type containing a static <TT>bool</TT> constant named <TT>value</TT> (no suffix).
|
|
||||||
The latter version interoperates with Boost.MPL. <BR>
|
|
||||||
<BR>
|
|
||||||
The definitions of <TT>enable_if_c</TT> and <TT>enable_if</TT> are as follows (we use <TT>enable_if</TT> templates
|
|
||||||
unqualified but they are in the <TT>boost</TT> namespace).
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <bool B, class T = void>
|
|
||||||
struct enable_if_c {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct enable_if_c<false, T> {};
|
|
||||||
|
|
||||||
template <class Cond, class T = void>
|
|
||||||
struct enable_if : public enable_if_c<Cond::value, T> {};
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
An instantiation of the <TT>enable_if_c</TT> template with the parameter
|
|
||||||
<TT>B</TT> as <TT>true</TT> contains a member type <TT>type</TT>, defined
|
|
||||||
to be <TT>T</TT>. If <TT>B</TT> is
|
|
||||||
<TT>false</TT>, no such member is defined. Thus
|
|
||||||
<TT>enable_if_c<B, T>::type</TT> is either a valid or an invalid type
|
|
||||||
expression, depending on the value of <TT>B</TT>.
|
|
||||||
When valid, <TT>enable_if_c<B, T>::type</TT> equals <TT>T</TT>.
|
|
||||||
The <TT>enable_if_c</TT> template can thus be used for controlling when functions are considered for
|
|
||||||
overload resolution and when they are not.
|
|
||||||
For example, the following function is defined for all arithmetic types (according to the
|
|
||||||
classification of the <A HREF="http://www.boost.org/libs/type_traits">Boost type_traits library</A>):
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if_c<boost::is_arithmetic<T>::value, T>::type
|
|
||||||
foo(T t) { return t; }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
The <TT>disable_if_c</TT> template is provided as well, and has the
|
|
||||||
same functionality as <TT>enable_if_c</TT> except for the negated condition. The following
|
|
||||||
function is enabled for all non-arithmetic types.
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename disable_if_c<boost::is_arithmetic<T>::value, T>::type
|
|
||||||
bar(T t) { return t; }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
For easier syntax in some cases and interoperation with Boost.MPL we provide versions of
|
|
||||||
the <TT>enable_if</TT> templates taking any type with a <TT>bool</TT> member constant named
|
|
||||||
<TT>value</TT> as the condition argument.
|
|
||||||
The MPL <TT>bool_</TT>, <TT>and_</TT>, <TT>or_</TT>, and <TT>not_</TT> templates are likely to be
|
|
||||||
useful for creating such types. Also, the traits classes in the Boost.Type_traits library
|
|
||||||
follow this convention.
|
|
||||||
For example, the above example function <TT>foo</TT> can be alternatively written as:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t) { return t; }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
<!--TOC section Using <TT>enable_if</TT>-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc5">3</A> Using <TT>enable_if</TT></H2><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:using_enable_if"></A>
|
|
||||||
The <TT>enable_if</TT> templates are defined in
|
|
||||||
<TT>boost/utility/enable_if.hpp</TT>, which is included by <TT>boost/utility.hpp</TT>.<BR>
|
|
||||||
<BR>
|
|
||||||
The <TT>enable_if</TT> template can be used either as the return type, or as an
|
|
||||||
extra argument. For example, the <TT>foo</TT> function in the previous section could also be written
|
|
||||||
as:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);
|
|
||||||
|
|
||||||
</PRE>Hence, an extra parameter of type <TT>void*</TT> is added, but it is given
|
|
||||||
a default value to keep the parameter hidden from client code.
|
|
||||||
Note that the second template argument was not given to <TT>enable_if</TT>, as the default
|
|
||||||
<TT>void</TT> gives the desired behavior.<BR>
|
|
||||||
<BR>
|
|
||||||
Whether to write the enabler as an argument or within the return type is
|
|
||||||
largely a matter of taste, but for certain functions, only one
|
|
||||||
alternative is possible:
|
|
||||||
<UL><LI>
|
|
||||||
Operators have a fixed number of arguments, thus <TT>enable_if</TT> must be used in the return type.
|
|
||||||
<LI>Constructors and destructors do not have a return type; an extra argument is the only option.
|
|
||||||
<LI>There does not seem to be a way to specify an enabler for a conversion operator. Converting constructors,
|
|
||||||
however, can have enablers as extra default arguments.
|
|
||||||
</UL>
|
|
||||||
<!--TOC subsection Enabling template class specializations-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc6">3.1</A> Enabling template class specializations</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:enable_if_classes"></A>
|
|
||||||
Class template specializations can be enabled or disabled with <TT>enable_if</TT>.
|
|
||||||
One extra template parameter needs to be added for the enabler expressions.
|
|
||||||
This parameter has the default value <TT>void</TT>.
|
|
||||||
For example:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T, class Enable = void>
|
|
||||||
class A { ... };
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class A<T, typename enable_if<is_integral<T> >::type> { ... };
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class A<T, typename enable_if<is_float<T> >::type> { ... };
|
|
||||||
|
|
||||||
</PRE>Instantiating <TT>A</TT> with any integral type matches the first specialization,
|
|
||||||
whereas any floating point type matches the second one. All other types
|
|
||||||
match the primary template.
|
|
||||||
The condition can be any compile-time boolean expression that depends on the
|
|
||||||
template arguments of the class.
|
|
||||||
Note that again, the second argument to <TT>enable_if</TT> is not needed; the default (<TT>void</TT>)
|
|
||||||
is the correct value.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Overlapping enabler conditions-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc7">3.2</A> Overlapping enabler conditions</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:overlapping_conditions"></A>
|
|
||||||
Once the compiler has examined the enabling conditions and included the
|
|
||||||
function into the overload resolution set, normal C++ overload resolution
|
|
||||||
rules are used to select the best matching function.
|
|
||||||
In particular, there is no ordering between enabling conditions.
|
|
||||||
Function templates with enabling conditions that are not mutually exclusive can
|
|
||||||
lead to ambiguities. For example:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_integral<T>, void>::type
|
|
||||||
foo(T t) {}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, void>::type
|
|
||||||
foo(T t) {}
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
All integral types are also arithmetic. Therefore, say, for the call <TT>foo(1)</TT>,
|
|
||||||
both conditions are true and both functions are thus in the overload resolution set.
|
|
||||||
They are both equally good matches and thus ambiguous.
|
|
||||||
Of course, more than one enabling condition can be simultaneously true as long as
|
|
||||||
other arguments disambiguate the functions.<BR>
|
|
||||||
<BR>
|
|
||||||
The above discussion applies to using <TT>enable_if</TT> in class template
|
|
||||||
partial specializations as well.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Lazy <TT>enable_if</TT>-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc8">3.3</A> Lazy <TT>enable_if</TT></H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:enable_if_lazy"></A>
|
|
||||||
In some cases it is necessary to avoid instantiating part of a
|
|
||||||
function signature unless an enabling condition is true. For example:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T, class U> class mult_traits;
|
|
||||||
|
|
||||||
template <class T, class U>
|
|
||||||
typename enable_if<is_multipliable<T, U>, typename mult_traits<T, U>::type>::type
|
|
||||||
operator*(const T& t, const U& u) { ... }
|
|
||||||
|
|
||||||
</PRE>Assume the class template <TT>mult_traits</TT> is a traits class defining
|
|
||||||
the resulting type of a multiplication operator. The <TT>is_multipliable</TT> traits
|
|
||||||
class specifies for which types to enable the operator. Whenever
|
|
||||||
<TT>is_multipliable<A, B>::value</TT> is <TT>true</TT> for some types <TT>A</TT> and <TT>B</TT>,
|
|
||||||
then <TT>mult_traits<A, B>::type</TT> is defined.<BR>
|
|
||||||
<BR>
|
|
||||||
Now, trying to invoke (some other overload) of <TT>operator*</TT> with, say, operand types <TT>C</TT> and <TT>D</TT>
|
|
||||||
for which <TT>is_multipliable<C, D>::value</TT> is <TT>false</TT>
|
|
||||||
and <TT>mult_traits<C, D>::type</TT> is not defined is an error on some compilers.
|
|
||||||
The SFINAE principle is not applied because
|
|
||||||
the invalid type occurs as an argument to another template. The <TT>lazy_enable_if</TT>
|
|
||||||
and <TT>lazy_disable_if</TT> templates (and their <TT>_c</TT> versions) can be used in such
|
|
||||||
situations:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template<class T, class U>
|
|
||||||
typename lazy_enable_if<is_multipliable<T, U>, mult_traits<T, U> >::type
|
|
||||||
operator*(const T& t, const U& u) { ... }
|
|
||||||
|
|
||||||
</PRE>The second argument of <TT>lazy_enable_if</TT> must be a class type
|
|
||||||
that defines a nested type named <TT>type</TT> whenever the first
|
|
||||||
parameter (the condition) is true.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC paragraph Note-->
|
|
||||||
|
|
||||||
<H5>Note</H5><!--SEC END -->
|
|
||||||
|
|
||||||
Referring to one member type or static constant in a traits class
|
|
||||||
causes all of the members (type and static constant) of that
|
|
||||||
specialization to be instantiated. Therefore, if your traits classes
|
|
||||||
can sometimes contain invalid types, you should use two distinct
|
|
||||||
templates for describing the conditions and the type mappings. In the
|
|
||||||
above example, <TT>is_multipliable<T, U>::value</TT> defines when
|
|
||||||
<TT>mult_traits<T, U>::type</TT> is valid.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Compiler workarounds-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc9">3.4</A> Compiler workarounds</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:workarounds"></A>
|
|
||||||
Some compilers flag functions as ambiguous if the only distinguishing factor is a different
|
|
||||||
condition in an enabler (even though the functions could never be ambiguous). For example,
|
|
||||||
some compilers (e.g. GCC 3.2) diagnose the following two functions as ambiguous:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
|
|
||||||
</PRE>Two workarounds can be applied:
|
|
||||||
<UL><LI>
|
|
||||||
Use an extra dummy parameter which disambiguates the functions. Use a default value for
|
|
||||||
it to hide the parameter from the caller. For example:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
template <class T> struct dummy { dummy(int) {} };
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t, dummy<0> = 0);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t, dummy<1> = 0);
|
|
||||||
</PRE><BR>
|
|
||||||
<BR>
|
|
||||||
<LI>Define the functions in different namespaces and bring them into a common
|
|
||||||
namespace with <TT>using</TT> declarations:
|
|
||||||
<PRE>
|
|
||||||
|
|
||||||
namespace A {
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace B {
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
}
|
|
||||||
|
|
||||||
using A::foo;
|
|
||||||
using B::foo;
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
Note that the second workaround above cannot be used for member
|
|
||||||
templates. On the other hand, operators do not accept extra arguments,
|
|
||||||
which makes the first workaround unusable. As the net effect,
|
|
||||||
neither of the workarounds are of assistance for templated operators that
|
|
||||||
need to be defined as member functions (assignment and
|
|
||||||
subscript operators).
|
|
||||||
</UL>
|
|
||||||
<!--TOC section Acknowledgements-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc10">4</A> Acknowledgements</H2><!--SEC END -->
|
|
||||||
|
|
||||||
We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides, and Richard
|
|
||||||
Smith whose findings have influenced the library.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC section References-->
|
|
||||||
|
|
||||||
<H2>References</H2><!--SEC END -->
|
|
||||||
<DL COMPACT=compact><DT><A NAME="jarvi:03:cuj_arbitrary_overloading"><FONT COLOR=purple>[1]</FONT></A><DD>
|
|
||||||
Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine.
|
|
||||||
Function overloading based on arbitrary properties of types.
|
|
||||||
<EM>C/C++ Users Journal</EM>, 21(6):25--32, June 2003.<BR>
|
|
||||||
<BR>
|
|
||||||
<DT><A NAME="jarvi:03:c++typeclasses"><FONT COLOR=purple>[2]</FONT></A><DD>
|
|
||||||
Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine.
|
|
||||||
Concept-controlled polymorphism.
|
|
||||||
In Frank Pfennig and Yannis Smaragdakis, editors, <EM>Generative
|
|
||||||
Programming and Component Engineering</EM>, volume 2830 of <EM>LNCS</EM>, pages
|
|
||||||
228--244. Springer Verlag, September 2003.<BR>
|
|
||||||
<BR>
|
|
||||||
<DT><A NAME="vandevoorde2002:templates"><FONT COLOR=purple>[3]</FONT></A><DD>
|
|
||||||
David Vandevoorde and Nicolai M. Josuttis.
|
|
||||||
<EM>C++ Templates: The Complete Guide</EM>.
|
|
||||||
Addison-Wesley, 2002.</DL>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<hr></hr>
|
|
||||||
|
|
||||||
<B>Contributed by:</B> <BR>
|
|
||||||
Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine<BR>
|
|
||||||
<EM>{jajarvi|jewillco|lums}@osl.iu.edu</EM><BR>
|
|
||||||
Indiana University<BR>
|
|
||||||
Open Systems Lab
|
|
||||||
<!--HTMLFOOT-->
|
|
||||||
<!--ENDHTML-->
|
|
||||||
<!--FOOTER-->
|
|
||||||
<HR SIZE=2>
|
|
||||||
<BLOCKQUOTE><EM>This document was translated from L<sup>A</sup>T<sub>E</sub>X by
|
|
||||||
</EM><A HREF="http://pauillac.inria.fr/~maranget/hevea/index.html"><EM>H<FONT SIZE=2><sup>E</sup></FONT>V<FONT SIZE=2><sup>E</sup></FONT>A</EM></A><EM>.
|
|
||||||
</EM></BLOCKQUOTE>
|
|
||||||
</BODY>
|
|
||||||
</HTML>
|
|
@@ -1,302 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
|
||||||
"http://www.w3.org/TR/html4/strict.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<!-- TODO:
|
|
||||||
- lambda interaction
|
|
||||||
-->
|
|
||||||
|
|
||||||
<title>Boost.Utility - lexicographic documentation</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
||||||
</head>
|
|
||||||
<body bgcolor="#ffffff">
|
|
||||||
<h1>
|
|
||||||
<img border="0" src="../../../c++boost.gif" align="center" alt="c++ boost">
|
|
||||||
Utility - Lexicographic
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The class <code>boost::lexicographic</code> provides an easy way
|
|
||||||
to avoid complex and errorprone if-else cascades to do lexicographic
|
|
||||||
comparisions on certain different criteria. The class is in the header
|
|
||||||
<a href="../../../boost/utility/lexicographic.hpp"
|
|
||||||
>boost/utility/lexicographic.hpp</a> and depends on no others headers.
|
|
||||||
The test code is in
|
|
||||||
<a href="../../../libs/utility/test/lexicographic_test.cpp"
|
|
||||||
>lexicographic_test.cpp</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2>Contents</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="#introduction">Introduction</a></li>
|
|
||||||
<li><a href="#examples">Examples</a></li>
|
|
||||||
<li><a href="#synopsis">Synopsis</a></li>
|
|
||||||
<li><a href="#members">Members</a></li>
|
|
||||||
<li><a href="#free_functions">Free Functions</a></li>
|
|
||||||
<li><a href="#credits">Credits</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h2><a name="introduction">Introduction</a></h2>
|
|
||||||
<p>
|
|
||||||
Often one has to write comparisions which give an ordering between
|
|
||||||
various kinds of data. When they look in a certain
|
|
||||||
specified order at one relation between two data items at a time and
|
|
||||||
result in a lexicographic comparision of all these relations the
|
|
||||||
programmer often has to write long if-else cascades. These cascades
|
|
||||||
are often complex and difficult to maintain. The class
|
|
||||||
<code>boost::lexicographic</code> helps in this scenario. Its constructor
|
|
||||||
and function call operator takes two data items which need to be
|
|
||||||
compared as arguments and performs to comparision. The order in which
|
|
||||||
the function call operators are called determine the lexicographic order
|
|
||||||
of the relations. Since the result of all further comparisions might not
|
|
||||||
be needed after a certain step, they are not executed.<br>
|
|
||||||
The logic of the class assumes an ascending order as implied by the
|
|
||||||
<code>operator <</code>. If a descending order needs to be obtained
|
|
||||||
one can just switch the order of the arguments. Additionally, both the
|
|
||||||
constructor and the function call operator provide also a three argument
|
|
||||||
form which takes a functor for comparisions as a third argument.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3>Relation to <code>std::lexicographic_compare</code></h3>
|
|
||||||
<p>
|
|
||||||
The standard C++ algorithm <code>std::lexicographic_compare</code>
|
|
||||||
does essentially the same thing but in a different situation. It compares
|
|
||||||
sequences of data items of equal type. Whereas <code>boost::lexicographic</code>
|
|
||||||
compares individual data items of different type, and every comparison
|
|
||||||
must be specified explicitly by using the function call operator of the class.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3>Relation to if-else-cascades</h3>
|
|
||||||
<p>
|
|
||||||
<b>Advantages</b><br>
|
|
||||||
<ul>
|
|
||||||
<li>The order of comparisons can easily be changed.
|
|
||||||
<li>Single comparisons can be added or removed in one line.
|
|
||||||
<li>Comparisons can be split up to be computed partly in one
|
|
||||||
function and partly in another by using
|
|
||||||
<code>boost::lexicographic</code> as a functor.
|
|
||||||
<li>It documents the code in a better fashion and expresses
|
|
||||||
the users intention directly.
|
|
||||||
<li>If the comparison arguments do not need computation, there is in
|
|
||||||
theory no performance overhead.
|
|
||||||
</ul>
|
|
||||||
<b>Disadvantages</b><br>
|
|
||||||
<ul>
|
|
||||||
<li>There is no short-circuiting. All arguments will be
|
|
||||||
evaluated, also if
|
|
||||||
an earlier comparison step already gave the final result. As long as the
|
|
||||||
arguments are trivial there should be no performance overhead. The only
|
|
||||||
way to avoid evaluation of arguments is to place every comparison step
|
|
||||||
in an if-statement like:
|
|
||||||
<blockquote>
|
|
||||||
<pre>boost::lexicographic cmp (complex_computation (a), complex_computation (b));
|
|
||||||
if (cmp.result () == lexicographic::equivalent)
|
|
||||||
{
|
|
||||||
cmp (complex_computation (c), complex_computation (d));
|
|
||||||
if (cmp.result () == lexicographic::equivalent)
|
|
||||||
{
|
|
||||||
cmp (complex_computation (e), complex_computation (f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// do something with cmp
|
|
||||||
</pre>
|
|
||||||
</blockquote>
|
|
||||||
But this construct eats up many of the advantages of using
|
|
||||||
<code>boost::lexicographic</code>.
|
|
||||||
<li>
|
|
||||||
The performance of using <code>boost::lexicographic</code>, besides
|
|
||||||
the lack of short-circuiting, is not negligible.
|
|
||||||
Tests with gcc 3.2.2 showed, that the algorithmic overhead
|
|
||||||
is about 40% in comparison to according to if-else-cascades.
|
|
||||||
Additionally gcc failed to inline everything properly, so that the
|
|
||||||
resulting performance overhead was about a factor two.
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2><a name="examples">Examples</a></h2>
|
|
||||||
<p>
|
|
||||||
An example usage are special sorting operators, such as the lexicographic
|
|
||||||
ordering of tuples:
|
|
||||||
<blockquote>
|
|
||||||
<pre>struct position
|
|
||||||
{
|
|
||||||
double x, y, z;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator < (position const &p1, position const &p2)
|
|
||||||
{
|
|
||||||
return boost::lexicographic (p1.x, p2.x)
|
|
||||||
(p1.y, p2.y)
|
|
||||||
(p1.z, p2.z);
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
An alternative form of writing this without <code>boost::lexicographic</code>
|
|
||||||
would be this:
|
|
||||||
<blockquote>
|
|
||||||
<pre>bool operator < (position const &p1, position const &p2)
|
|
||||||
{
|
|
||||||
if (p1.x == p2.x)
|
|
||||||
if (p1.y == p2.y)
|
|
||||||
return p1.z < p2.z;
|
|
||||||
else
|
|
||||||
return p1.y < p2.y;
|
|
||||||
else
|
|
||||||
return p1.x < p2.x;
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
It is also easy to use different functor such as a case insensitive
|
|
||||||
comparision function object in the next example.
|
|
||||||
<blockquote>
|
|
||||||
<pre>struct person
|
|
||||||
{
|
|
||||||
std::string firstname, lastname;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator < (person const &p1, person const &p2)
|
|
||||||
{
|
|
||||||
return boost::lexicographic
|
|
||||||
(p1.lastname, p2.lastname, cmp_case_insensitive)
|
|
||||||
(p1.firstname, p2.firstname, cmp_case_insensitive);
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2><a name="synopsis">Synopsis</a></h2>
|
|
||||||
<blockquote>
|
|
||||||
<pre>namespace boost
|
|
||||||
{
|
|
||||||
|
|
||||||
class lexicographic
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum result_type { minus = -1, equivalent, plus };
|
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
|
||||||
lexicographic (T1 const &a, T2 const &b);
|
|
||||||
|
|
||||||
template <typename T1, typename T2, typename Cmp>
|
|
||||||
lexicographic (T1 const &a, T2 const &b, Cmp cmp);
|
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
|
||||||
lexicographic &operator () (T1 const &a, T2 const &b);
|
|
||||||
|
|
||||||
template <typename T1, typename T2, typename Cmp>
|
|
||||||
lexicographic &operator () (T1 const &a, T2 const &b, Cmp cmp);
|
|
||||||
|
|
||||||
result_type result () const;
|
|
||||||
operator <i>unspecified_bool_type</i> () const;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator == (lexicographic l1, lexicographic l2);
|
|
||||||
bool operator != (lexicographic l1, lexicographic l2);
|
|
||||||
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
<h2><a name="members">Members</a></h2>
|
|
||||||
<h3>result_type</h3>
|
|
||||||
<code>enum result_type { minus = -1, equivalent = 0, plus = +1 };</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Defines the result type of the class. It is kept as internal state
|
|
||||||
and is returned by <code>result ()</code>.
|
|
||||||
The integer representation of it is equivalent to the one
|
|
||||||
returned by <code>std::strcmp</code>.
|
|
||||||
<ul>
|
|
||||||
<li><code>minus</code> - the sequence of the first arguments
|
|
||||||
of constructor and function call operators
|
|
||||||
is lexicographically less than the according
|
|
||||||
sequence of the second arguments.
|
|
||||||
<li><code>equivalent</code> - all elements of the sequences
|
|
||||||
of the first and the second arguments are identical.
|
|
||||||
<li><code>plus</code> - the sequence of the first arguments
|
|
||||||
of constructor and function call operators
|
|
||||||
is lexicographically greater than the according
|
|
||||||
sequence of the second arguments.
|
|
||||||
</ul>
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<h3>constructors</h3>
|
|
||||||
<code>template <typename T1, typename T2><br>
|
|
||||||
lexicographic (T1 const &a, T2 const &b);</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Constructs new object and does the first comparision
|
|
||||||
step between <code>a</code> and <code>b</code>. It uses
|
|
||||||
<code>operator <</code> for comparisions.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<code>template <typename T1, typename T2, typename Cmp><br>
|
|
||||||
lexicographic (T1 const &a, T2 const &b, Cmp cmp);</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Constructs new object and does the first comparision
|
|
||||||
step between <code>a</code> and <code>b</code>. It uses
|
|
||||||
<code>cmp</code> for comparisions.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<h3>function call operators</h3>
|
|
||||||
<code>template <typename T1, typename T2><br>
|
|
||||||
lexicographic &operator () (T1 const &a, T2 const &b);</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Does next comparision step on object between <code>a</code>
|
|
||||||
and <code>b</code>. It uses <code>operator <</code> for
|
|
||||||
comparisions.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<code>template <typename T1, typename T2, typename Cmp><br>
|
|
||||||
lexicographic &operator () (T1 const &a, T2 const &b, Cmp cmp);</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Does next comparision step on object between <code>a</code>
|
|
||||||
and <code>b</code>. It uses <code>cmp</code> for
|
|
||||||
comparisions.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<h3>result</h3>
|
|
||||||
<code>result_type result () const;</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Gives result of already done comparision steps.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<h3>conversions</h3>
|
|
||||||
<code>operator <i>unspecified_bool_type</i> () const;</code>
|
|
||||||
<blockquote><p>
|
|
||||||
This conversion operator allows objects to be used in boolean
|
|
||||||
contexts, like <code>if (lexicographic (a, b)) {}</code>. The
|
|
||||||
actual target type is typically a pointer to a member function,
|
|
||||||
avoiding many of the implicit conversion pitfalls.<br>
|
|
||||||
It evaluates to <code>true</code> if <code>result () == minus</code>,
|
|
||||||
otherwise to <code>false</code>.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<h2><a name="free_functions">Free Functions</a></h2>
|
|
||||||
<h3>comparision</h3>
|
|
||||||
<code>bool operator == (lexicographic l1, lexicographic l2);</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Returns <code>l1.result () == l2.result ()</code>.
|
|
||||||
That means it returns <code>true</code> if both
|
|
||||||
objects are in the same state.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<code>bool operator != (lexicographic l1, lexicographic l2);</code>
|
|
||||||
<blockquote><p>
|
|
||||||
Returns <code>l1.result () != l2.result ()</code>.
|
|
||||||
That means it returns <code>true</code> if the two
|
|
||||||
objects are in the a different state.
|
|
||||||
</p></blockquote>
|
|
||||||
|
|
||||||
<h2><a name="credits">Credits</a></h2>
|
|
||||||
<p>
|
|
||||||
The author of <code>boost::lexicographic</code> is Jan Langer (jan@langernetz.de).
|
|
||||||
Ideas and suggestions from Steve Cleary, David Abrahams, Gennaro Proata, Paul Bristow, Daniel Frey, Daryle Walker and Brian McNamara were used.
|
|
||||||
</p>
|
|
||||||
<hr>
|
|
||||||
<p>
|
|
||||||
October 5, 2003<br>
|
|
||||||
<br>
|
|
||||||
<09> Copyright Jan Langer 2003<br>
|
|
||||||
Use, modification, and distribution is subject to the Boost Software
|
|
||||||
License, Version 1.0. (See accompanying file
|
|
||||||
<a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at
|
|
||||||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,444 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<meta name="generator" content="Docutils 0.3.1: http://docutils.sourceforge.net/" />
|
|
||||||
<title>The Boost.NamedParams Library Boost</title>
|
|
||||||
<link rel="stylesheet" href="../../../rst.css" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="document" id="the-boost-namedparams-library-logo">
|
|
||||||
<h1 class="title">The Boost.NamedParams Library <a class="reference" href="../../../index.htm"><img alt="Boost" class="boost-logo" src="../../../c++boost.gif" /></a></h1>
|
|
||||||
<hr />
|
|
||||||
<table class="field-list" frame="void" rules="none">
|
|
||||||
<col class="field-name" />
|
|
||||||
<col class="field-body" />
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr class="field"><th class="field-name">Authors:</th><td class="field-body">David Abrahams, Daniel Wallin</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="field"><th class="field-name">Contact:</th><td class="field-body"><a class="reference" href="mailto:dave@boost-consulting.com">dave@boost-consulting.com</a>, <a class="reference" href="mailto:dalwan01@student.umu.se">dalwan01@student.umu.se</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="field"><th class="field-name">organizations:</th><td class="field-body"><a class="reference" href="http://www.boost-consulting.com">Boost Consulting</a>,</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="field"><th class="field-name">date:</th><td class="field-body">$Date$</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="field"><th class="field-name">copyright:</th><td class="field-body">Copyright David Abrahams, Daniel Wallin 2003.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="field"><th class="field-name">license:</th><td class="field-body">Use, modification and distribution is subject to the
|
|
||||||
Boost Software License, Version 1.0. (See accompanying
|
|
||||||
file LICENSE_1_0.txt or copy at
|
|
||||||
<a class="reference" href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="contents topic" id="outline">
|
|
||||||
<p class="topic-title"><a name="outline">Outline</a></p>
|
|
||||||
<ul class="auto-toc simple">
|
|
||||||
<li><a class="reference" href="#introduction" id="id7" name="id7">1 Introduction</a></li>
|
|
||||||
<li><a class="reference" href="#tutorial" id="id8" name="id8">2 Tutorial</a><ul class="auto-toc">
|
|
||||||
<li><a class="reference" href="#defining-the-keywords" id="id9" name="id9">2.1 Defining the keywords</a></li>
|
|
||||||
<li><a class="reference" href="#defining-the-forwarding-functions" id="id10" name="id10">2.2 Defining the forwarding functions</a></li>
|
|
||||||
<li><a class="reference" href="#defining-the-implementation-function" id="id11" name="id11">2.3 Defining the implementation function</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><a class="reference" href="#limitations-of-the-approach" id="id12" name="id12">3 Limitations of the Approach</a></li>
|
|
||||||
<li><a class="reference" href="#controlling-overload-resolution" id="id13" name="id13">4 Controlling Overload Resolution</a></li>
|
|
||||||
<li><a class="reference" href="#lazy-evaluation-of-defaults" id="id14" name="id14">5 Lazy Evaluation of Defaults</a></li>
|
|
||||||
<li><a class="reference" href="#automatic-overload-generation" id="id15" name="id15">6 Automatic Overload Generation</a></li>
|
|
||||||
<li><a class="reference" href="#portability" id="id16" name="id16">7 Portability</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="introduction">
|
|
||||||
<h1><a class="toc-backref" href="#id7" name="introduction">1 Introduction</a></h1>
|
|
||||||
<p>In C++ function arguments are given meaning by their position in
|
|
||||||
the parameter list. This protocol is fine when there are few
|
|
||||||
parameters with default values, but as the number of parameters
|
|
||||||
grows, so does the inconvenience of passing arguments in the
|
|
||||||
correct order, especially in the presence of default values:</p>
|
|
||||||
<blockquote>
|
|
||||||
<ul>
|
|
||||||
<li><p class="first">It can become difficult for readers to understand the meaning of
|
|
||||||
arguments at the call site:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
window* w = new_window("alert", true, true, false, 77, 65);
|
|
||||||
</pre>
|
|
||||||
</li>
|
|
||||||
<li><p class="first">Since meaning is given by position, we have to choose some
|
|
||||||
(often arbitrary) order for parameters with default values,
|
|
||||||
making some combinations of defaults unusable:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
window* new_window(
|
|
||||||
char const* name, bool border = true
|
|
||||||
, bool opaque = true, bool movable = false
|
|
||||||
, int width = 100, int height = 100);
|
|
||||||
|
|
||||||
const bool movability = true;
|
|
||||||
window* w = new_window("alert2", movability); // error!
|
|
||||||
</pre>
|
|
||||||
</li>
|
|
||||||
<li><p class="first">Default values can not depend on the values of other function
|
|
||||||
parameters:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
window* new_window(
|
|
||||||
char const* name, bool border, ...
|
|
||||||
, int width = 100, int heigh = width); // error!
|
|
||||||
</pre>
|
|
||||||
</li>
|
|
||||||
<li><p class="first">Template types can not be deduced from the default values, so
|
|
||||||
we have to resort to overloading to provide default values for
|
|
||||||
parameters with template type:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
template<class T> void f(T x = 0);
|
|
||||||
|
|
||||||
f(); // error!
|
|
||||||
</pre>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
<p>This library is an attempt to address the problems outlined above
|
|
||||||
by associating each parameter with a keyword identifier. Using
|
|
||||||
this library, users can identify parameters by name instead of just
|
|
||||||
argument position:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
window* w = new_window("alert2", movable = movability); // OK!
|
|
||||||
</pre>
|
|
||||||
<!-- DWA Daniel, we explicitly *don't* need ref() for the case
|
|
||||||
described below. It's only when we want to pass by reference
|
|
||||||
without a keyword that we need it.
|
|
||||||
|
|
||||||
You also can't start talking about forwarding functions without
|
|
||||||
introducing them first!
|
|
||||||
|
|
||||||
The tutorial has to come before all the nasty details below.
|
|
||||||
I'm going to comment on that and leave the next stuff alone -->
|
|
||||||
</div>
|
|
||||||
<div class="section" id="tutorial">
|
|
||||||
<h1><a class="toc-backref" href="#id8" name="tutorial">2 Tutorial</a></h1>
|
|
||||||
<!-- DWA you need some set-up here describing the problem you're
|
|
||||||
going to solve. -->
|
|
||||||
<p>This example shows how to wrap a function:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
void foo(char const* name, float value);
|
|
||||||
</pre>
|
|
||||||
<p>to give both parameters names and default values.</p>
|
|
||||||
<div class="section" id="defining-the-keywords">
|
|
||||||
<h2><a class="toc-backref" href="#id9" name="defining-the-keywords">2.1 Defining the keywords</a></h2>
|
|
||||||
<p>First we define the named parameter keywords. This is done by creating
|
|
||||||
"tag" types for each keyword, and declaring <tt class="literal"><span class="pre">keyword<</span></tt><em>tag</em><tt class="literal"><span class="pre">></span></tt> objects:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
#include <boost/named_params.hpp>
|
|
||||||
|
|
||||||
struct name_t; // tag types
|
|
||||||
struct value_t;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
boost::keyword<name_t> name; // keyword objects
|
|
||||||
boost::keyword<value_t> value;
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>Placing these keyword objects in an unnamed namespace will prevent
|
|
||||||
link errors when you declare keywords in header files [<strong>Note</strong>:
|
|
||||||
the tag types should generally <em>not</em> be declared in an unnamed
|
|
||||||
namespace]. We also need to create a keywords list for our
|
|
||||||
function. These keywords should be declared in the same order as
|
|
||||||
their corresponding parameters appear in the function's parameter
|
|
||||||
list:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
struct foo_keywords
|
|
||||||
: boost::keywords<
|
|
||||||
name_t
|
|
||||||
, value_t
|
|
||||||
>
|
|
||||||
{};
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="defining-the-forwarding-functions">
|
|
||||||
<h2><a class="toc-backref" href="#id10" name="defining-the-forwarding-functions">2.2 Defining the forwarding functions</a></h2>
|
|
||||||
<pre class="literal-block">
|
|
||||||
template<class Params>
|
|
||||||
void foo_impl(const Params&);
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
foo_impl(foo_keywords());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0>
|
|
||||||
void foo(const A0& a0)
|
|
||||||
{
|
|
||||||
foo_impl(foo_keywords(a0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0, class A1>
|
|
||||||
void foo(const A0& a0, const A1& a1)
|
|
||||||
{
|
|
||||||
foo_impl(foo_keywords(a0, a1));
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="defining-the-implementation-function">
|
|
||||||
<h2><a class="toc-backref" href="#id11" name="defining-the-implementation-function">2.3 Defining the implementation function</a></h2>
|
|
||||||
<pre class="literal-block">
|
|
||||||
template<class Params>
|
|
||||||
void foo_impl(const Params& params)
|
|
||||||
{
|
|
||||||
std::cout << params[name] << " = " << params[value] << "\n";
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>That's it. The user calls the <tt class="literal"><span class="pre">foo()</span></tt> forwarding functions, with
|
|
||||||
either positional or named parameters. For instance:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
foo("bar", 3.14f);
|
|
||||||
foo(value = 6.28f, "baz")
|
|
||||||
</pre>
|
|
||||||
<p>Should print:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
bar = 3.14
|
|
||||||
baz = 6.28
|
|
||||||
</pre>
|
|
||||||
<p>But we still don't have any default values, leaving any of the
|
|
||||||
parameters out results in a compilation error:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
foo()
|
|
||||||
foo("bar")
|
|
||||||
foo(value = 3)
|
|
||||||
</pre>
|
|
||||||
<p>All fails.</p>
|
|
||||||
<p>Fortunatly, adding default values to parameters is easy:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
template<class Params>
|
|
||||||
void foo_impl(const Params& params)
|
|
||||||
{
|
|
||||||
std::cout
|
|
||||||
<< params[name | "unnamed"] << " = "
|
|
||||||
<< params[value | 0] << "\n";
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>We are using <tt class="literal"><span class="pre">operator|</span></tt> to denote the default value of a named
|
|
||||||
parameter.</p>
|
|
||||||
<p>Going back a little to the <tt class="literal"><span class="pre">foo()</span></tt> call that didn't compile:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
foo()
|
|
||||||
foo("bar")
|
|
||||||
foo(value = 3)
|
|
||||||
</pre>
|
|
||||||
<p>Now compiles, and prints:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
unnamed = 0
|
|
||||||
bar = 0
|
|
||||||
unnamed = 3
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="limitations-of-the-approach">
|
|
||||||
<h1><a class="toc-backref" href="#id12" name="limitations-of-the-approach">3 Limitations of the Approach</a></h1>
|
|
||||||
<p>Because the keywords' <tt class="literal"><span class="pre">operator=</span></tt> returns a temporary, and
|
|
||||||
temporaries cannot be bound to non-<tt class="literal"><span class="pre">const</span></tt> reference parameters,
|
|
||||||
our forwarding functions need to take their arguments by <tt class="literal"><span class="pre">const</span></tt>
|
|
||||||
reference <a class="footnote-reference" href="#forwarding" id="id2" name="id2"><sup>1</sup></a>. As a result, an argument which is bound
|
|
||||||
to a keyword with <tt class="literal"><span class="pre">operator=</span></tt> can be transparently passed by
|
|
||||||
non-const reference, but positional arguments are always passed by
|
|
||||||
<tt class="literal"><span class="pre">const</span></tt> reference unless we use the <a class="reference" href="../../bind/ref.hpp">Boost.Ref</a> library to
|
|
||||||
indicate otherwise:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
#include <boost/ref.hpp>
|
|
||||||
|
|
||||||
float x;
|
|
||||||
foo(value = x); // held type is float&
|
|
||||||
foo(x); // held type is float const&, need help!
|
|
||||||
foo(boost::ref(x)); // held type is float&
|
|
||||||
</pre>
|
|
||||||
<p>Instances of <tt class="literal"><span class="pre">boost::reference_wrapper<></span></tt> generated by
|
|
||||||
<tt class="literal"><span class="pre">boost::ref</span></tt> will be unwrapped automatically by the library.</p>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="controlling-overload-resolution">
|
|
||||||
<h1><a class="toc-backref" href="#id13" name="controlling-overload-resolution">4 Controlling Overload Resolution</a></h1>
|
|
||||||
<p>The parameters of our templated forwarding functions are completely
|
|
||||||
general; in fact, they're a perfect match for any argument type
|
|
||||||
whatsoever. The problems with exposing such general function
|
|
||||||
templates have been the subject of much discussion; especially in
|
|
||||||
the presence of <a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225">unqualified calls</a>. Probably the safest thing
|
|
||||||
to do is to isolate the forwarding functions in a namespace
|
|
||||||
containing no types <a class="footnote-reference" href="#using" id="id3" name="id3"><sup>2</sup></a>, but often we'd <em>like</em> our functions
|
|
||||||
to play nicely with argument-dependent lookup and other function
|
|
||||||
overloads. In that case, it's neccessary to somehow remove the
|
|
||||||
functions from the overload set when the passed argument types
|
|
||||||
don't meet their needs.</p>
|
|
||||||
<p>This sort of overload control can be accomplished in C++ by taking
|
|
||||||
advantage of <a class="reference" href="http://www.semantics.org/once_weakly/w02_SFINAE.pdf">SFINAE</a> (Substitution Failure Is Not An Error). If
|
|
||||||
type substitution during the instantiation of a function template
|
|
||||||
results in an invalid type, no compilation error is emitted;
|
|
||||||
instead the overload is removed from the overload set. By producing
|
|
||||||
an invalid type in the function signature depending on the result
|
|
||||||
of some condition, whether or not an overload is considered during
|
|
||||||
overload resolution can be controlled. The technique is formalized
|
|
||||||
in the <tt class="literal"><span class="pre">enable_if</span></tt> utility.</p>
|
|
||||||
<p>The named parameters library provides built-in SFINAE support
|
|
||||||
through the following class template:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
template<
|
|
||||||
class KeywordTag
|
|
||||||
, class HasDefaultValue // mpl::true_ or mpl::false_
|
|
||||||
, class Predicate
|
|
||||||
>
|
|
||||||
struct named_param;
|
|
||||||
</pre>
|
|
||||||
<p>The key parameter, <tt class="literal"><span class="pre">Predicate</span></tt> shall be a unary MPL lambda
|
|
||||||
expression or <a class="reference" href="../../mpl/doc/ref/Metafunction_Class.html">Metafunction Class</a> that, when applied to the
|
|
||||||
actual type the argument, indicates whether that argument type
|
|
||||||
meets the function's requirements for that parameter position.</p>
|
|
||||||
<p>For example, let's say we want to restrict our <tt class="literal"><span class="pre">foo()</span></tt> so that
|
|
||||||
the <tt class="literal"><span class="pre">name</span></tt> parameter must be convertible to <tt class="literal"><span class="pre">const</span> <span class="pre">char*</span></tt>.
|
|
||||||
We'll replace our use of the <tt class="literal"><span class="pre">name_t</span></tt> tag with a specialization
|
|
||||||
of <tt class="literal"><span class="pre">boost::named_param</span></tt>:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
struct foo_keywords
|
|
||||||
: boost::keywords<
|
|
||||||
<strong>boost::named_param<
|
|
||||||
name_t
|
|
||||||
, mpl::false_
|
|
||||||
, is_convertible<mpl::_, const char*>
|
|
||||||
></strong>
|
|
||||||
, value_t
|
|
||||||
>
|
|
||||||
{};
|
|
||||||
</pre>
|
|
||||||
<p>Now we can add an additional optional argument to each of our
|
|
||||||
<tt class="literal"><span class="pre">foo</span></tt> overloads</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
template<class A0>
|
|
||||||
void foo(
|
|
||||||
const A0& a0
|
|
||||||
, <strong>foo_keywords::restrict<A0>::type x = foo_keywords()</strong>
|
|
||||||
)
|
|
||||||
{
|
|
||||||
foo_impl(x(a0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0, class A1>
|
|
||||||
void foo(
|
|
||||||
const A0& a0, const A1& a1
|
|
||||||
, <strong>foo_keywords::restrict<A0,A1>::type x = foo_keywords()</strong>
|
|
||||||
)
|
|
||||||
{
|
|
||||||
foo_impl(x(a0, a1));
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
<p>These additional parameters are not intended to be used directly
|
|
||||||
by callers; they merely trigger SFINAE by becoming illegal types
|
|
||||||
when the <tt class="literal"><span class="pre">name</span></tt> argument is not convertible to <tt class="literal"><span class="pre">const</span> <span class="pre">char*</span></tt>.</p>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="lazy-evaluation-of-defaults">
|
|
||||||
<h1><a class="toc-backref" href="#id14" name="lazy-evaluation-of-defaults">5 Lazy Evaluation of Defaults</a></h1>
|
|
||||||
<p>If computing an argument's default value is expensive, it's best
|
|
||||||
avoided when the argument is supplied by the user. In that case,
|
|
||||||
the default value can be lazily evaluated using the following
|
|
||||||
syntax:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
params[keyword <strong>|| nullary_function</strong>];
|
|
||||||
</pre>
|
|
||||||
<p><tt class="literal"><span class="pre">nullary_function</span></tt> must be a function object that is callable
|
|
||||||
without arguments, and that indicates its return type via a nested
|
|
||||||
<tt class="literal"><span class="pre">result_type</span></tt>. Boost.Bind can be used to produce an appropriate
|
|
||||||
function object from a regular function pointer:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
// expensive default computation function
|
|
||||||
float default_span(float x, float theta);
|
|
||||||
|
|
||||||
// implementation of bar()
|
|
||||||
template <class Params>
|
|
||||||
void bar_impl(Params const& params)
|
|
||||||
{
|
|
||||||
// Extract arguments
|
|
||||||
float x_ = params[x];
|
|
||||||
float theta_ = params[theta | pi];
|
|
||||||
float span = params[span || boost::bind(default_span, x_, theta_)];
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="automatic-overload-generation">
|
|
||||||
<h1><a class="toc-backref" href="#id15" name="automatic-overload-generation">6 Automatic Overload Generation</a></h1>
|
|
||||||
<p>To reduce the work needed to write functions with named parameters,
|
|
||||||
we supply a macro that generates the boilerplate code.</p>
|
|
||||||
<p>Synopsis:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
BOOST_NAMED_PARAMS_FUN(
|
|
||||||
return_type, function_name
|
|
||||||
, min_arity, max_arity, keywords_type
|
|
||||||
);
|
|
||||||
</pre>
|
|
||||||
<p>To generate all the forwarding functions and the implementation
|
|
||||||
function for our example, we need only apply
|
|
||||||
<tt class="literal"><span class="pre">BOOST_NAMED_PARAMS_FUN</span></tt> this way:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
BOOST_NAMED_PARAMS_FUN(void, foo, 0, 2, foo_keywords)
|
|
||||||
{
|
|
||||||
std::cout
|
|
||||||
<< p[name | "unnamed"] << " = "
|
|
||||||
<< p[value | 0] << "\n";
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="portability">
|
|
||||||
<h1><a class="toc-backref" href="#id16" name="portability">7 Portability</a></h1>
|
|
||||||
<p>Boost.NamedParams has been confirmed to work on the following compilers:</p>
|
|
||||||
<blockquote>
|
|
||||||
<ul class="simple">
|
|
||||||
<li>Microsoft VC6 sp5, VC7 <a class="footnote-reference" href="#norestrict" id="id5" name="id5"><sup>3</sup></a></li>
|
|
||||||
<li>Microsoft VC7.1</li>
|
|
||||||
<li>GCC3.3.1 (cygwin), GCC2.95.3 (cygwin), GCC3.2 (mingw)</li>
|
|
||||||
<li>Metrowerks Codewarrior Pro8 and Pro9 (Windows)</li>
|
|
||||||
<li>Intel C++ 5.0,6.0,7.1,8.0 (Windows)</li>
|
|
||||||
<li>Comeau 4.3.3</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
<hr />
|
|
||||||
<table class="footnote" frame="void" id="forwarding" rules="none">
|
|
||||||
<colgroup><col class="label" /><col /></colgroup>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td class="label"><a class="fn-backref" href="#id2" name="forwarding">[1]</a></td><td><p>One could provide overloads for <tt class="literal"><span class="pre">const</span></tt> and
|
|
||||||
non-<tt class="literal"><span class="pre">const</span></tt> reference versions of each parameter, but that
|
|
||||||
would quickly become unmanageable. It's known as "the
|
|
||||||
forwarding problem" and has been described in detail in this
|
|
||||||
<a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm">paper</a>. The combinatorial explosion is avoided for the
|
|
||||||
parameter of keywords' <tt class="literal"><span class="pre">operator=</span></tt> because they take only a
|
|
||||||
single argument.</p>
|
|
||||||
</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table class="footnote" frame="void" id="using" rules="none">
|
|
||||||
<colgroup><col class="label" /><col /></colgroup>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td class="label"><a class="fn-backref" href="#id3" name="using">[2]</a></td><td><p>You can always give the illusion that the function
|
|
||||||
lives in an outer namespace by applying a <em>using-declaration</em>:</p>
|
|
||||||
<pre class="literal-block">
|
|
||||||
namespace foo_overloads
|
|
||||||
{
|
|
||||||
// foo declarations here
|
|
||||||
void foo() { ... }
|
|
||||||
...
|
|
||||||
}
|
|
||||||
using foo_overloads::foo;
|
|
||||||
</pre>
|
|
||||||
</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table class="footnote" frame="void" id="norestrict" rules="none">
|
|
||||||
<colgroup><col class="label" /><col /></colgroup>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td class="label"><a class="fn-backref" href="#id5" name="norestrict">[3]</a></td><td>Restrictions doesn't work on these compilers because
|
|
||||||
of lack of SFINAE support.</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr class="footer" />
|
|
||||||
<div class="footer">
|
|
||||||
<a class="reference" href="named_params.rst">View document source</a>.
|
|
||||||
Generated on: 2004-03-04 10:40 UTC.
|
|
||||||
Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,427 +0,0 @@
|
|||||||
++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
The Boost.NamedParams Library |(logo)|__
|
|
||||||
++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
.. |(logo)| image:: ../../../c++boost.gif
|
|
||||||
:alt: Boost
|
|
||||||
:class: boost-logo
|
|
||||||
|
|
||||||
__ ../../../index.htm
|
|
||||||
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
:Authors: David Abrahams, Daniel Wallin
|
|
||||||
:Contact: dave@boost-consulting.com, dalwan01@student.umu.se
|
|
||||||
:organizations: `Boost Consulting`_,
|
|
||||||
:date: $Date$
|
|
||||||
:copyright: Copyright David Abrahams, Daniel Wallin 2003.
|
|
||||||
:license: Use, modification and distribution is subject to 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)
|
|
||||||
|
|
||||||
.. _`Boost Consulting`: http://www.boost-consulting.com
|
|
||||||
.. _`Open Systems Lab`: http://www.osl.iu.edu
|
|
||||||
|
|
||||||
.. contents:: Outline
|
|
||||||
.. section-numbering::
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
============
|
|
||||||
|
|
||||||
In C++ function arguments are given meaning by their position in
|
|
||||||
the parameter list. This protocol is fine when there are few
|
|
||||||
parameters with default values, but as the number of parameters
|
|
||||||
grows, so does the inconvenience of passing arguments in the
|
|
||||||
correct order, especially in the presence of default values:
|
|
||||||
|
|
||||||
* It can become difficult for readers to understand the meaning of
|
|
||||||
arguments at the call site::
|
|
||||||
|
|
||||||
window* w = new_window("alert", true, true, false, 77, 65);
|
|
||||||
|
|
||||||
* Since meaning is given by position, we have to choose some
|
|
||||||
(often arbitrary) order for parameters with default values,
|
|
||||||
making some combinations of defaults unusable::
|
|
||||||
|
|
||||||
window* new_window(
|
|
||||||
char const* name, bool border = true
|
|
||||||
, bool opaque = true, bool movable = false
|
|
||||||
, int width = 100, int height = 100);
|
|
||||||
|
|
||||||
const bool movability = true;
|
|
||||||
window* w = new_window("alert2", movability); // error!
|
|
||||||
|
|
||||||
* Default values can not depend on the values of other function
|
|
||||||
parameters::
|
|
||||||
|
|
||||||
window* new_window(
|
|
||||||
char const* name, bool border, ...
|
|
||||||
, int width = 100, int heigh = width); // error!
|
|
||||||
|
|
||||||
* Template types can not be deduced from the default values, so
|
|
||||||
we have to resort to overloading to provide default values for
|
|
||||||
parameters with template type::
|
|
||||||
|
|
||||||
template<class T> void f(T x = 0);
|
|
||||||
|
|
||||||
f(); // error!
|
|
||||||
|
|
||||||
This library is an attempt to address the problems outlined above
|
|
||||||
by associating each parameter with a keyword identifier. Using
|
|
||||||
this library, users can identify parameters by name instead of just
|
|
||||||
argument position::
|
|
||||||
|
|
||||||
window* w = new_window("alert2", movable = movability); // OK!
|
|
||||||
|
|
||||||
|
|
||||||
.. DWA Daniel, we explicitly *don't* need ref() for the case
|
|
||||||
described below. It's only when we want to pass by reference
|
|
||||||
without a keyword that we need it.
|
|
||||||
|
|
||||||
You also can't start talking about forwarding functions without
|
|
||||||
introducing them first!
|
|
||||||
|
|
||||||
The tutorial has to come before all the nasty details below.
|
|
||||||
I'm going to comment on that and leave the next stuff alone
|
|
||||||
|
|
||||||
Tutorial
|
|
||||||
========
|
|
||||||
|
|
||||||
.. DWA you need some set-up here describing the problem you're
|
|
||||||
going to solve.
|
|
||||||
|
|
||||||
This example shows how to wrap a function::
|
|
||||||
|
|
||||||
void foo(char const* name, float value);
|
|
||||||
|
|
||||||
to give both parameters names and default values.
|
|
||||||
|
|
||||||
Defining the keywords
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
First we define the named parameter keywords. This is done by creating
|
|
||||||
"tag" types for each keyword, and declaring ``keyword<``\ *tag*\
|
|
||||||
``>`` objects::
|
|
||||||
|
|
||||||
#include <boost/named_params.hpp>
|
|
||||||
|
|
||||||
struct name_t; // tag types
|
|
||||||
struct value_t;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
boost::keyword<name_t> name; // keyword objects
|
|
||||||
boost::keyword<value_t> value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Placing these keyword objects in an unnamed namespace will prevent
|
|
||||||
link errors when you declare keywords in header files [**Note**:
|
|
||||||
the tag types should generally *not* be declared in an unnamed
|
|
||||||
namespace]. We also need to create a keywords list for our
|
|
||||||
function. These keywords should be declared in the same order as
|
|
||||||
their corresponding parameters appear in the function's parameter
|
|
||||||
list::
|
|
||||||
|
|
||||||
struct foo_keywords
|
|
||||||
: boost::keywords<
|
|
||||||
name_t
|
|
||||||
, value_t
|
|
||||||
>
|
|
||||||
{};
|
|
||||||
|
|
||||||
Defining the forwarding functions
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
template<class Params>
|
|
||||||
void foo_impl(const Params&);
|
|
||||||
|
|
||||||
void foo()
|
|
||||||
{
|
|
||||||
foo_impl(foo_keywords());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0>
|
|
||||||
void foo(const A0& a0)
|
|
||||||
{
|
|
||||||
foo_impl(foo_keywords(a0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0, class A1>
|
|
||||||
void foo(const A0& a0, const A1& a1)
|
|
||||||
{
|
|
||||||
foo_impl(foo_keywords(a0, a1));
|
|
||||||
}
|
|
||||||
|
|
||||||
Defining the implementation function
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
template<class Params>
|
|
||||||
void foo_impl(const Params& params)
|
|
||||||
{
|
|
||||||
std::cout << params[name] << " = " << params[value] << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
That's it. The user calls the ``foo()`` forwarding functions, with
|
|
||||||
either positional or named parameters. For instance::
|
|
||||||
|
|
||||||
foo("bar", 3.14f);
|
|
||||||
foo(value = 6.28f, "baz")
|
|
||||||
|
|
||||||
Should print::
|
|
||||||
|
|
||||||
bar = 3.14
|
|
||||||
baz = 6.28
|
|
||||||
|
|
||||||
But we still don't have any default values, leaving any of the
|
|
||||||
parameters out results in a compilation error::
|
|
||||||
|
|
||||||
foo()
|
|
||||||
foo("bar")
|
|
||||||
foo(value = 3)
|
|
||||||
|
|
||||||
All fails.
|
|
||||||
|
|
||||||
Fortunatly, adding default values to parameters is easy::
|
|
||||||
|
|
||||||
template<class Params>
|
|
||||||
void foo_impl(const Params& params)
|
|
||||||
{
|
|
||||||
std::cout
|
|
||||||
<< params[name | "unnamed"] << " = "
|
|
||||||
<< params[value | 0] << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
We are using ``operator|`` to denote the default value of a named
|
|
||||||
parameter.
|
|
||||||
|
|
||||||
Going back a little to the ``foo()`` call that didn't compile::
|
|
||||||
|
|
||||||
foo()
|
|
||||||
foo("bar")
|
|
||||||
foo(value = 3)
|
|
||||||
|
|
||||||
Now compiles, and prints::
|
|
||||||
|
|
||||||
unnamed = 0
|
|
||||||
bar = 0
|
|
||||||
unnamed = 3
|
|
||||||
|
|
||||||
Limitations of the Approach
|
|
||||||
===========================
|
|
||||||
|
|
||||||
Because the keywords' ``operator=`` returns a temporary, and
|
|
||||||
temporaries cannot be bound to non-``const`` reference parameters,
|
|
||||||
our forwarding functions need to take their arguments by ``const``
|
|
||||||
reference [#forwarding]_. As a result, an argument which is bound
|
|
||||||
to a keyword with ``operator=`` can be transparently passed by
|
|
||||||
non-const reference, but positional arguments are always passed by
|
|
||||||
``const`` reference unless we use the `Boost.Ref`_ library to
|
|
||||||
indicate otherwise::
|
|
||||||
|
|
||||||
#include <boost/ref.hpp>
|
|
||||||
|
|
||||||
float x;
|
|
||||||
foo(value = x); // held type is float&
|
|
||||||
foo(x); // held type is float const&, need help!
|
|
||||||
foo(boost::ref(x)); // held type is float&
|
|
||||||
|
|
||||||
.. _`Boost.Ref`: ../../bind/ref.hpp
|
|
||||||
|
|
||||||
|
|
||||||
Instances of ``boost::reference_wrapper<>`` generated by
|
|
||||||
``boost::ref`` will be unwrapped automatically by the library.
|
|
||||||
|
|
||||||
Controlling Overload Resolution
|
|
||||||
===============================
|
|
||||||
|
|
||||||
The parameters of our templated forwarding functions are completely
|
|
||||||
general; in fact, they're a perfect match for any argument type
|
|
||||||
whatsoever. The problems with exposing such general function
|
|
||||||
templates have been the subject of much discussion; especially in
|
|
||||||
the presence of `unqualified calls`__. Probably the safest thing
|
|
||||||
to do is to isolate the forwarding functions in a namespace
|
|
||||||
containing no types [#using]_, but often we'd *like* our functions
|
|
||||||
to play nicely with argument-dependent lookup and other function
|
|
||||||
overloads. In that case, it's neccessary to somehow remove the
|
|
||||||
functions from the overload set when the passed argument types
|
|
||||||
don't meet their needs.
|
|
||||||
|
|
||||||
__ http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#225
|
|
||||||
|
|
||||||
This sort of overload control can be accomplished in C++ by taking
|
|
||||||
advantage of SFINAE_ (Substitution Failure Is Not An Error). If
|
|
||||||
type substitution during the instantiation of a function template
|
|
||||||
results in an invalid type, no compilation error is emitted;
|
|
||||||
instead the overload is removed from the overload set. By producing
|
|
||||||
an invalid type in the function signature depending on the result
|
|
||||||
of some condition, whether or not an overload is considered during
|
|
||||||
overload resolution can be controlled. The technique is formalized
|
|
||||||
in the |enable_if| utility.
|
|
||||||
|
|
||||||
The named parameters library provides built-in SFINAE support
|
|
||||||
through the following class template::
|
|
||||||
|
|
||||||
template<
|
|
||||||
class KeywordTag
|
|
||||||
, class HasDefaultValue // mpl::true_ or mpl::false_
|
|
||||||
, class Predicate
|
|
||||||
>
|
|
||||||
struct named_param;
|
|
||||||
|
|
||||||
The key parameter, ``Predicate`` shall be a unary MPL lambda
|
|
||||||
expression or `Metafunction Class`_ that, when applied to the
|
|
||||||
actual type the argument, indicates whether that argument type
|
|
||||||
meets the function's requirements for that parameter position.
|
|
||||||
|
|
||||||
.. _`Metafunction Class`: ../../mpl/doc/ref/Metafunction_Class.html
|
|
||||||
|
|
||||||
.. _SFINAE: http://www.semantics.org/once_weakly/w02_SFINAE.pdf
|
|
||||||
|
|
||||||
.. |enable_if| replace:: ``enable_if``
|
|
||||||
.. _enable_if: ../enable_if.html
|
|
||||||
|
|
||||||
For example, let's say we want to restrict our ``foo()`` so that
|
|
||||||
the ``name`` parameter must be convertible to ``const char*``.
|
|
||||||
We'll replace our use of the ``name_t`` tag with a specialization
|
|
||||||
of ``boost::named_param``:
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
struct foo_keywords
|
|
||||||
: boost::keywords<
|
|
||||||
**boost::named_param<
|
|
||||||
name_t
|
|
||||||
, mpl::false\_
|
|
||||||
, is_convertible<mpl::\_, const char\*>
|
|
||||||
>**
|
|
||||||
, value_t
|
|
||||||
>
|
|
||||||
{};
|
|
||||||
|
|
||||||
Now we can add an additional optional argument to each of our
|
|
||||||
``foo`` overloads
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
template<class A0>
|
|
||||||
void foo(
|
|
||||||
const A0& a0
|
|
||||||
, **foo_keywords::restrict<A0>::type x = foo_keywords()**
|
|
||||||
)
|
|
||||||
{
|
|
||||||
foo_impl(x(a0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0, class A1>
|
|
||||||
void foo(
|
|
||||||
const A0& a0, const A1& a1
|
|
||||||
, **foo_keywords::restrict<A0,A1>::type x = foo_keywords()**
|
|
||||||
)
|
|
||||||
{
|
|
||||||
foo_impl(x(a0, a1));
|
|
||||||
}
|
|
||||||
|
|
||||||
These additional parameters are not intended to be used directly
|
|
||||||
by callers; they merely trigger SFINAE by becoming illegal types
|
|
||||||
when the ``name`` argument is not convertible to ``const char*``.
|
|
||||||
|
|
||||||
Lazy Evaluation of Defaults
|
|
||||||
===========================
|
|
||||||
|
|
||||||
If computing an argument's default value is expensive, it's best
|
|
||||||
avoided when the argument is supplied by the user. In that case,
|
|
||||||
the default value can be lazily evaluated using the following
|
|
||||||
syntax:
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
params[keyword **|| nullary_function**];
|
|
||||||
|
|
||||||
``nullary_function`` must be a function object that is callable
|
|
||||||
without arguments, and that indicates its return type via a nested
|
|
||||||
``result_type``. Boost.Bind can be used to produce an appropriate
|
|
||||||
function object from a regular function pointer::
|
|
||||||
|
|
||||||
// expensive default computation function
|
|
||||||
float default_span(float x, float theta);
|
|
||||||
|
|
||||||
// implementation of bar()
|
|
||||||
template <class Params>
|
|
||||||
void bar_impl(Params const& params)
|
|
||||||
{
|
|
||||||
// Extract arguments
|
|
||||||
float x_ = params[x];
|
|
||||||
float theta_ = params[theta | pi];
|
|
||||||
float span = params[span || boost::bind(default_span, x_, theta_)];
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
Automatic Overload Generation
|
|
||||||
=============================
|
|
||||||
|
|
||||||
To reduce the work needed to write functions with named parameters,
|
|
||||||
we supply a macro that generates the boilerplate code.
|
|
||||||
|
|
||||||
Synopsis::
|
|
||||||
|
|
||||||
BOOST_NAMED_PARAMS_FUN(
|
|
||||||
return_type, function_name
|
|
||||||
, min_arity, max_arity, keywords_type
|
|
||||||
);
|
|
||||||
|
|
||||||
To generate all the forwarding functions and the implementation
|
|
||||||
function for our example, we need only apply
|
|
||||||
``BOOST_NAMED_PARAMS_FUN`` this way::
|
|
||||||
|
|
||||||
BOOST_NAMED_PARAMS_FUN(void, foo, 0, 2, foo_keywords)
|
|
||||||
{
|
|
||||||
std::cout
|
|
||||||
<< p[name | "unnamed"] << " = "
|
|
||||||
<< p[value | 0] << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
Portability
|
|
||||||
===========
|
|
||||||
|
|
||||||
Boost.NamedParams has been confirmed to work on the following compilers:
|
|
||||||
|
|
||||||
- Microsoft VC6 sp5, VC7 [#norestrict]_
|
|
||||||
- Microsoft VC7.1
|
|
||||||
- GCC3.3.1 (cygwin), GCC2.95.3 (cygwin), GCC3.2 (mingw)
|
|
||||||
- Metrowerks Codewarrior Pro8 and Pro9 (Windows)
|
|
||||||
- Intel C++ 5.0,6.0,7.1,8.0 (Windows)
|
|
||||||
- Comeau 4.3.3
|
|
||||||
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
.. [#forwarding] One could provide overloads for ``const`` and
|
|
||||||
non-``const`` reference versions of each parameter, but that
|
|
||||||
would quickly become unmanageable. It's known as "the
|
|
||||||
forwarding problem" and has been described in detail in this
|
|
||||||
paper__. The combinatorial explosion is avoided for the
|
|
||||||
parameter of keywords' ``operator=`` because they take only a
|
|
||||||
single argument.
|
|
||||||
|
|
||||||
__ http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
|
|
||||||
|
|
||||||
|
|
||||||
.. [#using] You can always give the illusion that the function
|
|
||||||
lives in an outer namespace by applying a *using-declaration*::
|
|
||||||
|
|
||||||
namespace foo_overloads
|
|
||||||
{
|
|
||||||
// foo declarations here
|
|
||||||
void foo() { ... }
|
|
||||||
...
|
|
||||||
}
|
|
||||||
using foo_overloads::foo;
|
|
||||||
|
|
||||||
.. [#norestrict] Restrictions doesn't work on these compilers because
|
|
||||||
of lack of SFINAE support.
|
|
||||||
|
|
@@ -1,167 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
|
||||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
|
|
||||||
<library name="Tribool" dirname="utility/tribool" id="tribool"
|
|
||||||
last-revision="$Date$" xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<libraryinfo>
|
|
||||||
<author>
|
|
||||||
<firstname>Douglas</firstname>
|
|
||||||
<surname>Gregor</surname>
|
|
||||||
<email>gregod@cs.rpi.edu</email>
|
|
||||||
</author>
|
|
||||||
|
|
||||||
<copyright>
|
|
||||||
<year>2002</year>
|
|
||||||
<year>2003</year>
|
|
||||||
<holder>Douglas Gregor</holder>
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>Permission to copy, use, sell and distribute this software
|
|
||||||
is granted provided this copyright notice appears in all copies.
|
|
||||||
Permission to modify the code and to distribute modified code is
|
|
||||||
granted provided this copyright notice appears in all copies, and
|
|
||||||
a notice that the code was modified is included with the copyright
|
|
||||||
notice. </para>
|
|
||||||
|
|
||||||
<para> This software is provided "as is" without express or
|
|
||||||
implied warranty, and with no claim as to its suitability for any
|
|
||||||
purpose. </para>
|
|
||||||
</legalnotice>
|
|
||||||
|
|
||||||
<librarypurpose>Three-state boolean type</librarypurpose>
|
|
||||||
<librarycategory name="category:misc"/>
|
|
||||||
</libraryinfo>
|
|
||||||
|
|
||||||
<section id="tribool.introduction">
|
|
||||||
<title>Introduction</title>
|
|
||||||
|
|
||||||
<para>The 3-state boolean library contains a single class,
|
|
||||||
<code><classname>boost::tribool</classname></code>, along with
|
|
||||||
support functions and operator overloads that implement 3-state
|
|
||||||
boolean logic. </para>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="tribool.tutorial">
|
|
||||||
<title>Tutorial</title>
|
|
||||||
|
|
||||||
<using-namespace name="boost"/>
|
|
||||||
|
|
||||||
<para> The <code><classname>tribool</classname></code> class acts
|
|
||||||
like the built-in <code>bool</code> type, but for 3-state boolean
|
|
||||||
logic. The three states are <code>true</code>, <code>false</code>,
|
|
||||||
and <code><functionname>indeterminate</functionname></code>, where
|
|
||||||
the first two states are equivalent to those of the C++
|
|
||||||
<code>bool</code> type and the last state represents an unknown
|
|
||||||
boolean value (that may be <code>true</code> or
|
|
||||||
<code>false</code>, we don't know).</para>
|
|
||||||
|
|
||||||
<para> The <code><classname>tribool</classname></code> class
|
|
||||||
supports conversion from <code>bool</code> values and literals
|
|
||||||
along with its own
|
|
||||||
<code><functionname>indeterminate</functionname></code>
|
|
||||||
keyword:</para>
|
|
||||||
|
|
||||||
<programlisting><classname>tribool</classname> b(true);
|
|
||||||
b = false;
|
|
||||||
b = <functionname>indeterminate</functionname>;
|
|
||||||
<classname>tribool</classname> b2(b);</programlisting>
|
|
||||||
|
|
||||||
<para> <code><classname>tribool</classname></code> supports
|
|
||||||
conversions to <code>bool</code> for use in conditional
|
|
||||||
statements. The conversion to <code>bool</code> will be
|
|
||||||
<code>true</code> when the value of the
|
|
||||||
<code><classname>tribool</classname></code> is always true, and
|
|
||||||
<code>false</code> otherwise.</para>
|
|
||||||
|
|
||||||
<programlisting><classname>tribool</classname> b = some_operation();
|
|
||||||
if (b) {
|
|
||||||
// b is true
|
|
||||||
}
|
|
||||||
else if (!b) {
|
|
||||||
// b is false
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// b is indeterminate
|
|
||||||
}</programlisting>
|
|
||||||
|
|
||||||
<para> <code><classname>tribool</classname></code> supports the
|
|
||||||
3-state logic operators <code>!</code> (negation),
|
|
||||||
<code>&&</code> (AND), and <code>||</code> (OR), with
|
|
||||||
<code>bool</code> and <code><classname>tribool</classname></code>
|
|
||||||
values. For instance:</para>
|
|
||||||
|
|
||||||
<programlisting><classname>tribool</classname> x = some_op();
|
|
||||||
<classname>tribool</classname> y = some_other_op();
|
|
||||||
if (x && y) {
|
|
||||||
// both x and y are true
|
|
||||||
}
|
|
||||||
else if (!(x && y)) {
|
|
||||||
// either x or y is false
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// neither x nor y is false, but we don't know that both are true
|
|
||||||
|
|
||||||
if (x || y) {
|
|
||||||
// either x or y is true, or both
|
|
||||||
}
|
|
||||||
}</programlisting>
|
|
||||||
|
|
||||||
<para> Similarly, <code><classname>tribool</classname></code>
|
|
||||||
supports 3-state equality comparisons via the operators
|
|
||||||
<code>==</code> and <code>!=</code>. These operators differ from
|
|
||||||
"normal" equality operators in C++ because they return a
|
|
||||||
<code><classname>tribool</classname></code>, because potentially we
|
|
||||||
might not know the result of a comparison (try to compare
|
|
||||||
<code>true</code> and
|
|
||||||
<code><functionname>indeterminate</functionname></code>). For
|
|
||||||
example:</para>
|
|
||||||
|
|
||||||
<programlisting><classname>tribool</classname> x(true);
|
|
||||||
<classname>tribool</classname> y(<functionname>indeterminate</functionname>);
|
|
||||||
|
|
||||||
assert(x == x); // okay, x == x returns true
|
|
||||||
assert(!(y == y)); // okay, because y == y is <functionname>indeterminate</functionname>
|
|
||||||
assert(x == true); // okay, can compare <classname>tribool</classname>s and bools</programlisting>
|
|
||||||
|
|
||||||
<para> The <code><functionname>indeterminate</functionname></code> keyword (representing the
|
|
||||||
<functionname>indeterminate</functionname> <code><classname>tribool</classname></code> value)
|
|
||||||
doubles as a function to check if the value of a
|
|
||||||
<code><classname>tribool</classname></code> is indeterminate,
|
|
||||||
e.g.,</para>
|
|
||||||
|
|
||||||
<programlisting><classname>tribool</classname> x = try_to_do_something_tricky();
|
|
||||||
if (<functionname>indeterminate</functionname>(x)) {
|
|
||||||
// value of x is indeterminate
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// report success or failure of x
|
|
||||||
}</programlisting>
|
|
||||||
|
|
||||||
<para> Users may introduce additional keywords for the indeterminate
|
|
||||||
value in addition to the implementation-supplied
|
|
||||||
<code><functionname>indeterminate</functionname></code> using the
|
|
||||||
<code><macroname>BOOST_TRIBOOL_THIRD_STATE</macroname></code>
|
|
||||||
macro. For instance, the following macro instantiation (at the
|
|
||||||
global scope) will introduce the keyword <code>maybe</code> as a
|
|
||||||
synonym for <code><functionname>indeterminate</functionname></code>
|
|
||||||
(also residing in the <code>boost</code> namespace):</para>
|
|
||||||
<programlisting><macroname>BOOST_TRIBOOL_THIRD_STATE</macroname>(maybe)</programlisting>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<xi:include href="reference.boostbook"/>
|
|
||||||
|
|
||||||
<testsuite>
|
|
||||||
<run-test filename="tribool_test.cpp">
|
|
||||||
<purpose><para>Test all features of the
|
|
||||||
<code><classname>boost::tribool</classname></code>
|
|
||||||
class.</para></purpose>
|
|
||||||
</run-test>
|
|
||||||
|
|
||||||
<run-test filename="tribool_rename_test.cpp">
|
|
||||||
<purpose><para>Test the use of the
|
|
||||||
<code><macroname>BOOST_TRIBOOL_THIRD_STATE</macroname></code>
|
|
||||||
macro.</para></purpose>
|
|
||||||
</run-test>
|
|
||||||
</testsuite>
|
|
||||||
</library>
|
|
@@ -1,249 +0,0 @@
|
|||||||
#ifndef BOOST_REF_HPP_INCLUDED
|
|
||||||
# define BOOST_REF_HPP_INCLUDED
|
|
||||||
|
|
||||||
# if _MSC_VER+0 >= 1020
|
|
||||||
# pragma once
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# include <boost/config.hpp>
|
|
||||||
# include <boost/utility/addressof.hpp>
|
|
||||||
# include <boost/type_traits/ice.hpp>
|
|
||||||
# include <boost/type.hpp>
|
|
||||||
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
# include <boost/result_of.hpp>
|
|
||||||
# endif
|
|
||||||
# include <boost/preprocessor/iterate.hpp>
|
|
||||||
# include <boost/pending/ct_if.hpp>
|
|
||||||
|
|
||||||
//
|
|
||||||
// ref.hpp - ref/cref, useful helper functions
|
|
||||||
//
|
|
||||||
// Copyright (C) 1999, 2000 Jaakko J<>rvi (jaakko.jarvi@cs.utu.fi)
|
|
||||||
// Copyright (C) 2001, 2002 Peter Dimov
|
|
||||||
// Copyright (C) 2002 David Abrahams
|
|
||||||
// Copyright (C) 2003 Doug Gregor
|
|
||||||
//
|
|
||||||
// Permission to copy, use, modify, sell and distribute this software
|
|
||||||
// is granted provided this copyright notice appears in all copies.
|
|
||||||
// This software is provided "as is" without express or implied
|
|
||||||
// warranty, and with no claim as to its suitability for any purpose.
|
|
||||||
//
|
|
||||||
// See http://www.boost.org/libs/bind/ref.html for documentation.
|
|
||||||
//
|
|
||||||
|
|
||||||
# ifndef BOOST_REF_NUM_ARGS
|
|
||||||
# define BOOST_REF_NUM_ARGS 10
|
|
||||||
# endif
|
|
||||||
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail { namespace ref {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class reference_wrapper_without_result_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<typename F>
|
|
||||||
struct result_of
|
|
||||||
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
: boost::result_of<F>
|
|
||||||
# endif
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
operator T& () const { return *(this->t_); }
|
|
||||||
T& get() const { return *(this->t_); }
|
|
||||||
T* get_pointer() const { return this->t_; }
|
|
||||||
|
|
||||||
# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
|
|
||||||
&& !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
|
|
||||||
# define BOOST_PP_ITERATION_PARAMS_1 (3,(0,BOOST_REF_NUM_ARGS,<boost/detail/ref_iterate.hpp>))
|
|
||||||
# include BOOST_PP_ITERATE()
|
|
||||||
# endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
# if defined(BOOST_MSVC) && (BOOST_MSVC < 1300)
|
|
||||||
explicit reference_wrapper_without_result_type(T& t) : t_(&t) {}
|
|
||||||
# else
|
|
||||||
explicit reference_wrapper_without_result_type(T& t) : t_(addressof(t)) {}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
T* t_;
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
template<typename T>
|
|
||||||
class reference_wrapper_with_result_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef typename T::result_type result_type;
|
|
||||||
|
|
||||||
operator T& () const { return *(this->t_); }
|
|
||||||
T& get() const { return *(this->t_); }
|
|
||||||
T* get_pointer() const { return this->t_; }
|
|
||||||
|
|
||||||
result_type operator()() const { return get()(); }
|
|
||||||
|
|
||||||
# if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
|
|
||||||
# define BOOST_PP_ITERATION_PARAMS_1 (3,(0,BOOST_REF_NUM_ARGS,<boost/detail/ref_iterate.hpp>))
|
|
||||||
# include BOOST_PP_ITERATE()
|
|
||||||
# endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
# if defined(BOOST_MSVC) && (BOOST_MSVC < 1300)
|
|
||||||
explicit reference_wrapper_with_result_type(T& t) : t_(&t) {}
|
|
||||||
# else
|
|
||||||
explicit reference_wrapper_with_result_type(T& t) : t_(addressof(t)) {}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
T* t_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class reference_wrapper_impl :
|
|
||||||
public ct_if<(has_result_type<T>::value),
|
|
||||||
reference_wrapper_with_result_type<T>,
|
|
||||||
reference_wrapper_without_result_type<T> >::type
|
|
||||||
{
|
|
||||||
typedef typename ct_if<(has_result_type<T>::value),
|
|
||||||
reference_wrapper_with_result_type<T>,
|
|
||||||
reference_wrapper_without_result_type<T> >::type
|
|
||||||
inherited;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
reference_wrapper_impl(T& t) : inherited(t) {}
|
|
||||||
};
|
|
||||||
# else
|
|
||||||
template<typename T>
|
|
||||||
class reference_wrapper_impl : public reference_wrapper_without_result_type<T>
|
|
||||||
{
|
|
||||||
typedef reference_wrapper_without_result_type<T> inherited;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
reference_wrapper_impl(T& t) : inherited(t) {}
|
|
||||||
};
|
|
||||||
# endif
|
|
||||||
|
|
||||||
} } // end namespace detail::ref
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
class reference_wrapper : public detail::ref::reference_wrapper_impl<T>
|
|
||||||
{
|
|
||||||
typedef detail::ref::reference_wrapper_impl<T> inherited;
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef T type;
|
|
||||||
|
|
||||||
explicit reference_wrapper(T& t) : inherited(t) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
# if defined(__BORLANDC__) && (__BORLANDC__ <= 0x570)
|
|
||||||
# define BOOST_REF_CONST
|
|
||||||
# else
|
|
||||||
# define BOOST_REF_CONST const
|
|
||||||
# endif
|
|
||||||
|
|
||||||
template<class T> inline reference_wrapper<T> BOOST_REF_CONST ref(T & t)
|
|
||||||
{
|
|
||||||
return reference_wrapper<T>(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T> inline reference_wrapper<T const> BOOST_REF_CONST cref(T const & t)
|
|
||||||
{
|
|
||||||
return reference_wrapper<T const>(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
# undef BOOST_REF_CONST
|
|
||||||
|
|
||||||
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
template<typename T>
|
|
||||||
class is_reference_wrapper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class is_reference_wrapper<reference_wrapper<T> >
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class unwrap_reference
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class unwrap_reference<reference_wrapper<T> >
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
# else // no partial specialization
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
typedef char (&yes_reference_wrapper_t)[1];
|
|
||||||
typedef char (&no_reference_wrapper_t)[2];
|
|
||||||
|
|
||||||
no_reference_wrapper_t is_reference_wrapper_test(...);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
yes_reference_wrapper_t
|
|
||||||
is_reference_wrapper_test(type< reference_wrapper<T> >);
|
|
||||||
|
|
||||||
template<bool wrapped>
|
|
||||||
struct reference_unwrapper
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
struct apply
|
|
||||||
{
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct reference_unwrapper<true>
|
|
||||||
{
|
|
||||||
template <class T>
|
|
||||||
struct apply
|
|
||||||
{
|
|
||||||
typedef typename T::type type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class is_reference_wrapper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BOOST_STATIC_CONSTANT(
|
|
||||||
bool, value = (
|
|
||||||
sizeof(detail::is_reference_wrapper_test(type<T>()))
|
|
||||||
== sizeof(detail::yes_reference_wrapper_t)));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class unwrap_reference
|
|
||||||
: public detail::reference_unwrapper<
|
|
||||||
is_reference_wrapper<T>::value
|
|
||||||
>::template apply<T>
|
|
||||||
{};
|
|
||||||
|
|
||||||
# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
#endif // #ifndef BOOST_REF_HPP_INCLUDED
|
|
@@ -1,87 +0,0 @@
|
|||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
|
|
||||||
// Boost Software License - Version 1.0 - August 17th, 2003
|
|
||||||
|
|
||||||
// Permission is hereby granted, free of charge, to any person or organization
|
|
||||||
// obtaining a copy of the software and accompanying documentation covered by
|
|
||||||
// this license (the "Software") to use, reproduce, display, distribute,
|
|
||||||
// execute, and transmit the Software, and to prepare derivative works of the
|
|
||||||
// Software, and to permit third-parties to whom the Software is furnished to
|
|
||||||
// do so, all subject to the following:
|
|
||||||
|
|
||||||
// The copyright notices in the Software and this entire statement, including
|
|
||||||
// the above license grant, this restriction and the following disclaimer,
|
|
||||||
// must be included in all copies of the Software, in whole or in part, and
|
|
||||||
// all derivative works of the Software, unless such copies or derivative
|
|
||||||
// works are solely in the form of machine-executable object code generated by
|
|
||||||
// a source language processor.
|
|
||||||
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
||||||
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
||||||
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
||||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
// DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef BOOST_UTILITY_ENABLE_IF_HPP
|
|
||||||
#define BOOST_UTILITY_ENABLE_IF_HPP
|
|
||||||
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
|
|
||||||
template <bool B, class T = void>
|
|
||||||
struct enable_if_c {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct enable_if_c<false, T> {};
|
|
||||||
|
|
||||||
template <class Cond, class T = void>
|
|
||||||
struct enable_if : public enable_if_c<Cond::value, T> {};
|
|
||||||
|
|
||||||
template <bool B, class T>
|
|
||||||
struct lazy_enable_if_c {
|
|
||||||
typedef typename T::type type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct lazy_enable_if_c<false, T> {};
|
|
||||||
|
|
||||||
template <class Cond, class T>
|
|
||||||
struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};
|
|
||||||
|
|
||||||
|
|
||||||
template <bool B, class T = void>
|
|
||||||
struct disable_if_c {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct disable_if_c<true, T> {};
|
|
||||||
|
|
||||||
template <class Cond, class T = void>
|
|
||||||
struct disable_if : public disable_if_c<Cond::value, T> {};
|
|
||||||
|
|
||||||
template <bool B, class T>
|
|
||||||
struct lazy_disable_if_c {
|
|
||||||
typedef typename T::type type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct lazy_disable_if_c<true, T> {};
|
|
||||||
|
|
||||||
template <class Cond, class T>
|
|
||||||
struct lazy_disable_if : public lazy_disable_if_c<Cond::value, T> {};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,105 +0,0 @@
|
|||||||
// Copyright (c) 2003 Jan Langer
|
|
||||||
// Use, modification, and distribution is subject to 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)
|
|
||||||
|
|
||||||
// See library home page at http://www.boost.org/libs/utility
|
|
||||||
|
|
||||||
#ifndef BOOST_UTILITY_LEXICOGRAPHIC_HPP
|
|
||||||
#define BOOST_UTILITY_LEXICOGRAPHIC_HPP
|
|
||||||
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
|
|
||||||
class lexicographic
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum result_type { minus = -1, equivalent = 0, plus = +1 };
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef void (lexicographic::*unspecified_bool_type) ();
|
|
||||||
void safe_bool_conversion () {}
|
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
|
||||||
result_type do_compare (T1 const &a, T2 const &b) const
|
|
||||||
{
|
|
||||||
if (a < b)
|
|
||||||
return minus;
|
|
||||||
else if (b < a)
|
|
||||||
return plus;
|
|
||||||
else
|
|
||||||
return equivalent;
|
|
||||||
}
|
|
||||||
template <typename T1, typename T2, typename Cmp>
|
|
||||||
result_type do_compare (T1 const &a, T2 const &b, Cmp cmp) const
|
|
||||||
{
|
|
||||||
if (cmp (a, b))
|
|
||||||
return minus;
|
|
||||||
else if (cmp (b, a))
|
|
||||||
return plus;
|
|
||||||
else
|
|
||||||
return equivalent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
lexicographic () : m_value (equivalent) {}
|
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
|
||||||
lexicographic (T1 const &a, T2 const &b)
|
|
||||||
: m_value (do_compare (a, b))
|
|
||||||
{}
|
|
||||||
template <typename T1, typename T2, typename Cmp>
|
|
||||||
lexicographic (T1 const &a, T2 const &b, Cmp cmp)
|
|
||||||
: m_value (do_compare (a, b, cmp))
|
|
||||||
{}
|
|
||||||
|
|
||||||
template <typename T1, typename T2>
|
|
||||||
lexicographic &operator () (T1 const &a, T2 const &b)
|
|
||||||
{
|
|
||||||
if (m_value == equivalent)
|
|
||||||
m_value = do_compare (a, b);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
template <typename T1, typename T2, typename Cmp>
|
|
||||||
lexicographic &operator () (T1 const &a, T2 const &b, Cmp cmp)
|
|
||||||
{
|
|
||||||
if (m_value == equivalent)
|
|
||||||
m_value = do_compare (a, b, cmp);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
result_type result () const
|
|
||||||
{
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator unspecified_bool_type () const
|
|
||||||
{
|
|
||||||
return (m_value == minus)
|
|
||||||
? &lexicographic::safe_bool_conversion
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// somehow only needed old compilers
|
|
||||||
bool operator ! () const
|
|
||||||
{
|
|
||||||
return m_value != minus;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
result_type m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator == (lexicographic l1, lexicographic l2)
|
|
||||||
{
|
|
||||||
return l1.result () == l2.result ();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator != (lexicographic l1, lexicographic l2)
|
|
||||||
{
|
|
||||||
return l1.result () != l2.result ();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
#endif // BOOST_UTILITY_LEXICOGRAPHIC_HPP
|
|
@@ -1,175 +0,0 @@
|
|||||||
// (C) Copyright Jonathan Turkanis 2004.
|
|
||||||
// Permission to copy, use, modify, sell and distribute this software
|
|
||||||
// is granted provided this copyright notice appears in all copies. This
|
|
||||||
// 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>. A single case with negative argument, case_<-1>, is also
|
|
||||||
// provided, for convenience.
|
|
||||||
//
|
|
||||||
// This header may be included any number of times, with
|
|
||||||
// BOOST_SELECT_BY_SIZE_MAX_CASE defined to be the largest N such that case_<N>
|
|
||||||
// is needed for a particular application. It defaults to 2.
|
|
||||||
//
|
|
||||||
// This header depends only on Boost.Config and Boost.Preprocessor. Dependence
|
|
||||||
// on Type Traits or MPL was intentionally avoided, to leave open the
|
|
||||||
// possibility that select_by_size could be used by these libraries.
|
|
||||||
//
|
|
||||||
// Example usage:
|
|
||||||
//
|
|
||||||
// #define BOOST_SELECT_BY_SIZE_MAX_CASE 7 // Needed for > 2 cases.
|
|
||||||
// #include <boost/utility/select_by_size.hpp>
|
|
||||||
//
|
|
||||||
// using namespace boost::utility;
|
|
||||||
//
|
|
||||||
// case_<0> helper(bool); // could use 'case_<false>' or 'no_type'.
|
|
||||||
// case_<1> helper(int); // could use 'case_<true>' 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_<N> with N > 2.
|
|
||||||
|
|
||||||
#ifndef BOOST_UTILITY_SELECT_BY_SIZE_HPP_INCLUDED
|
|
||||||
#define BOOST_UTILITY_SELECT_BY_SIZE_HPP_INCLUDED
|
|
||||||
|
|
||||||
// The lowest N for which select_by_size< sizeof(case_<N>) > has not been
|
|
||||||
// specialized.
|
|
||||||
#define SELECT_BY_SIZE_MAX_SPECIALIZED 2
|
|
||||||
|
|
||||||
#include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
|
|
||||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
|
||||||
#include <boost/preprocessor/cat.hpp>
|
|
||||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
|
||||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
|
||||||
|
|
||||||
/* Alternative implementation using max_align.
|
|
||||||
|
|
||||||
#include <boost/type_traits/alignment_of.hpp>
|
|
||||||
#include <boost/type_traits/type_with_alignment.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace utility {
|
|
||||||
|
|
||||||
template<int N>
|
|
||||||
struct case_ { char c[(N + 1) * alignment_of<detail::max_align>::value]; };
|
|
||||||
|
|
||||||
template<unsigned Size>
|
|
||||||
struct select_by_size {
|
|
||||||
BOOST_STATIC_CONSTANT(int, value =
|
|
||||||
(Size / alignment_of<detail::max_align>::value - 1));
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // End namespaces utility, boost.
|
|
||||||
|
|
||||||
*/ // End alternate implementation.
|
|
||||||
|
|
||||||
namespace boost { namespace utility {
|
|
||||||
|
|
||||||
//--------------Definition of case_-------------------------------------------//
|
|
||||||
|
|
||||||
template<int N> struct case_ { char c1; case_<N - 1> c2; };
|
|
||||||
template<> struct case_<-1> { char c; };
|
|
||||||
typedef case_<true> yes_type;
|
|
||||||
typedef case_<false> no_type;
|
|
||||||
|
|
||||||
//--------------Declaration of select_by_size---------------------------------//
|
|
||||||
|
|
||||||
template<unsigned Size> struct select_by_size;
|
|
||||||
|
|
||||||
} } // End namespaces utility, boost.
|
|
||||||
|
|
||||||
//--------------Definition of SELECT_BY_SIZE_SPEC-----------------------------//
|
|
||||||
|
|
||||||
// Sepecializes select_by_size for sizeof(case<n-1>). The decrement is used
|
|
||||||
// here because the preprocessor library doesn't handle negative integers.
|
|
||||||
#define SELECT_BY_SIZE_SPEC(n) \
|
|
||||||
namespace boost { namespace utility { \
|
|
||||||
namespace detail { \
|
|
||||||
static const int BOOST_PP_CAT(sizeof_case_, n) = sizeof(case_<n - 1>); \
|
|
||||||
} \
|
|
||||||
template<> \
|
|
||||||
struct select_by_size< detail::BOOST_PP_CAT(sizeof_case_, n) > { \
|
|
||||||
struct type { BOOST_STATIC_CONSTANT(int, value = n - 1); }; \
|
|
||||||
BOOST_STATIC_CONSTANT(int, value = type::value); \
|
|
||||||
}; \
|
|
||||||
} } \
|
|
||||||
/**/
|
|
||||||
|
|
||||||
//--------------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(type_, name, expr) \
|
|
||||||
BOOST_STATIC_CONSTANT( \
|
|
||||||
unsigned, \
|
|
||||||
BOOST_PP_CAT(boost_select_by_size_temp_, name) = sizeof(expr) \
|
|
||||||
); \
|
|
||||||
BOOST_STATIC_CONSTANT( \
|
|
||||||
type_, \
|
|
||||||
name = \
|
|
||||||
( boost::utility::select_by_size< \
|
|
||||||
BOOST_PP_CAT(boost_select_by_size_temp_, name) \
|
|
||||||
>::value ) \
|
|
||||||
) \
|
|
||||||
/**/
|
|
||||||
|
|
||||||
#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_<N>) 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 <boost/preprocessor/iteration/iterate.hpp>
|
|
||||||
#if !defined(BOOST_SELECT_BY_SIZE_MAX_CASE) || \
|
|
||||||
(BOOST_SELECT_BY_SIZE_MAX_CASE < 2)
|
|
||||||
#undef BOOST_SELECT_BY_SIZE_MAX_CASE
|
|
||||||
#define BOOST_SELECT_BY_SIZE_MAX_CASE 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (BOOST_SELECT_BY_SIZE_MAX_CASE > SELECT_BY_SIZE_MAX_SPECIALIZED)
|
|
||||||
#define BOOST_PP_FILENAME_1 <boost/utility/select_by_size.hpp>
|
|
||||||
#define BOOST_PP_ITERATION_LIMITS ( SELECT_BY_SIZE_MAX_SPECIALIZED, \
|
|
||||||
BOOST_SELECT_BY_SIZE_MAX_CASE )
|
|
||||||
#include BOOST_PP_ITERATE()
|
|
||||||
#undef SELECT_BY_SIZE_MAX_SPECIALIZED
|
|
||||||
#define SELECT_BY_SIZE_MAX_SPECIALIZED BOOST_SELECT_BY_SIZE_MAX_CASE
|
|
||||||
#endif // #if (BOOST_SELECT_BY_SIZE_CASES > SELECT_BY_SIZE_MAX_SPECIALIZED)
|
|
||||||
|
|
||||||
#undef BOOST_SELECT_BY_SIZE_MAX_CASE
|
|
||||||
#else // #if !BOOST_PP_IS_ITERATING //----------------------------------------//
|
|
||||||
SELECT_BY_SIZE_SPEC(BOOST_PP_INC(BOOST_PP_ITERATION()))
|
|
||||||
#endif // #if !BOOST_PP_IS_ITERATING //---------------------------------------//
|
|
@@ -1,476 +0,0 @@
|
|||||||
/*=============================================================================
|
|
||||||
Copyright (c) 2001-2003 Joel de Guzman
|
|
||||||
|
|
||||||
Use, modification and distribution is subject to 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)
|
|
||||||
==============================================================================*/
|
|
||||||
#ifndef BOOST_TYPE_DEDUCTION_IPP
|
|
||||||
#define BOOST_TYPE_DEDUCTION_IPP
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
Return Type Deduction
|
|
||||||
[JDG Sept. 15, 2003]
|
|
||||||
|
|
||||||
Before C++ adopts the typeof, there is currently no way to deduce the
|
|
||||||
result type of an expression such as x + y. This deficiency is a major
|
|
||||||
problem with template metaprogramming; for example, when writing
|
|
||||||
forwarding functions that attempt to capture the essence of an
|
|
||||||
expression inside a function. Consider the std::plus<T>:
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct plus : public binary_function<T, T, T>
|
|
||||||
{
|
|
||||||
T operator()(T const& x, T const& y) const
|
|
||||||
{
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
What's wrong with this? Well, this functor does not accurately capture
|
|
||||||
the behavior of the plus operator. 1) It does not handle the case where
|
|
||||||
x and y are of different types (e.g. x is short and y is int). 2) It
|
|
||||||
assumes that the arguments and return type are the same (i.e. when
|
|
||||||
adding a short and an int, the return type ought to be an int). Due to
|
|
||||||
these shortcomings, std::plus<T>(x, y) is a poor substitute for x + y.
|
|
||||||
|
|
||||||
The case where x is short and y is int does not really expose the
|
|
||||||
problem. We can simply use std::plus<int> and be happy that the
|
|
||||||
operands x and y will simply be converted to an int. The problem
|
|
||||||
becomes evident when an operand is a user defined type such as bigint.
|
|
||||||
Here, the conversion to bigint is simply not acceptable. Even if the
|
|
||||||
unnecessary conversion is tolerable, in generic code, it is not always
|
|
||||||
possible to choose the right T type that can accomodate both x and y
|
|
||||||
operands.
|
|
||||||
|
|
||||||
To truly model the plus operator, what we need is a polymorphic functor
|
|
||||||
that can take arbitrary x and y operands. Here's a rough schematic:
|
|
||||||
|
|
||||||
struct plus
|
|
||||||
{
|
|
||||||
template <typename X, typename Y>
|
|
||||||
unspecified-type
|
|
||||||
operator()(X const& x, Y const& y) const
|
|
||||||
{
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Now, we can handle the case where X and Y are arbitrary types. We've
|
|
||||||
solved the first problem. To solve the second problem, we need some
|
|
||||||
form of return type deduction mechanism. If we had the typeof, it would
|
|
||||||
be something like:
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typeof(X() + Y())
|
|
||||||
operator()(X const& x, Y const& y) const
|
|
||||||
{
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
Without the typeof facility, it is only possible to wrap an expression
|
|
||||||
such as x + y in a function or functor if we are given a hint that
|
|
||||||
tells us what the actual result type of such an expression is. Such a
|
|
||||||
hint can be in the form of a metaprogram, that, given the types of the
|
|
||||||
arguments, will return the result type. Example:
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
struct result_of_plus
|
|
||||||
{
|
|
||||||
typedef unspecified-type type;
|
|
||||||
};
|
|
||||||
|
|
||||||
Given a result_of_plus metaprogram, we can complete our polymorphic
|
|
||||||
plus functor:
|
|
||||||
|
|
||||||
struct plus
|
|
||||||
{
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename result_of_plus<X, Y>::type
|
|
||||||
operator()(X const& x, Y const& y) const
|
|
||||||
{
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
The process is not automatic. We have to specialize the metaprogram for
|
|
||||||
specific argument types. Examples:
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct result_of_plus<short, int>
|
|
||||||
{
|
|
||||||
typedef int type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct result_of_plus<std::complex<T>, std::complex<T> >
|
|
||||||
{
|
|
||||||
typedef std::complex<T> type;
|
|
||||||
};
|
|
||||||
|
|
||||||
To make it easier for the user, specializations are provided for common
|
|
||||||
types such as primitive c++ types (e.g. int, char, double, etc.), and
|
|
||||||
standard types (e.g. std::complex, iostream, std containers and
|
|
||||||
iterators).
|
|
||||||
|
|
||||||
To further improve the ease of use, for user defined classes, we can
|
|
||||||
supply a few more basic specializations through metaprogramming using
|
|
||||||
heuristics based on canonical operator rules (Such heuristics can be
|
|
||||||
found in the LL and Phoenix, for example). For example, it is rather
|
|
||||||
common that the result of x += y is X& or the result of x || y is a
|
|
||||||
bool. The client is out of luck if her classes do not follow the
|
|
||||||
canonical rules. She'll then have to supply her own specialization.
|
|
||||||
|
|
||||||
The type deduction mechanism demostrated below approaches the problem
|
|
||||||
not through specialization and heuristics, but through a limited form
|
|
||||||
of typeof mechanism. The code does not use heuristics, hence, no
|
|
||||||
guessing games. The code takes advantage of the fact that, in general,
|
|
||||||
the result type of an expression is related to one its arguments' type.
|
|
||||||
For example, x + y, where x has type int and y has type double, has the
|
|
||||||
result type double (the second operand type). Another example, x[y]
|
|
||||||
where x is a vector<T> and y is a std::size_t, has the result type
|
|
||||||
vector<T>::reference (the vector<T>'s reference type type).
|
|
||||||
|
|
||||||
The limited form of type deduction presented can detect common
|
|
||||||
relations if the result of a binary or unary operation, given arguments
|
|
||||||
x and y with types X and Y (respectively), is X, Y, X&, Y&, X*, Y*, X
|
|
||||||
const*, Y const*, bool, int, unsigned, double, container and iterator
|
|
||||||
elements (e.g the T, where X is: T[N], T*, vector<T>, map<T>,
|
|
||||||
vector<T>::iterator). More arguments/return type relationships can be
|
|
||||||
established if needed.
|
|
||||||
|
|
||||||
A set of overloaded test(T) functions capture these argument related
|
|
||||||
types. Each test(T) function returns a distinct type that can be used
|
|
||||||
to determine the exact type of an expression.
|
|
||||||
|
|
||||||
Consider:
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
x_value_type
|
|
||||||
test(X const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
y_value_type
|
|
||||||
test(Y const&);
|
|
||||||
|
|
||||||
Given an expression x + y, where x is int and y is double, the call to:
|
|
||||||
|
|
||||||
test<int, double>(x + y)
|
|
||||||
|
|
||||||
will return a y_value_type.
|
|
||||||
|
|
||||||
Now, if we rig x_value_type and y_value_type such that both have unique
|
|
||||||
sizes, we can use sizeof(test<X, Y>(x + y)) to determine if the result
|
|
||||||
type is either X or Y.
|
|
||||||
|
|
||||||
For example, if:
|
|
||||||
|
|
||||||
sizeof(test<X, Y>(x + y)) == sizeof(y_value_type)
|
|
||||||
|
|
||||||
then, we know for sure that the result of x + y has type Y.
|
|
||||||
|
|
||||||
The same basic scheme can be used to detect more argument-dependent
|
|
||||||
return types where the sizeof the test(T) return type is used to index
|
|
||||||
through a boost::mpl vector which holds each of the corresponding
|
|
||||||
result types.
|
|
||||||
|
|
||||||
==============================================================================*/
|
|
||||||
#include <boost/mpl/vector/vector20.hpp>
|
|
||||||
#include <boost/mpl/at.hpp>
|
|
||||||
#include <boost/mpl/not.hpp>
|
|
||||||
#include <boost/mpl/or.hpp>
|
|
||||||
#include <boost/mpl/and.hpp>
|
|
||||||
#include <boost/mpl/identity.hpp>
|
|
||||||
#include <boost/type_traits/remove_reference.hpp>
|
|
||||||
#include <boost/type_traits/remove_cv.hpp>
|
|
||||||
#include <boost/type_traits/is_const.hpp>
|
|
||||||
#include <boost/type_traits/is_reference.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
#include <boost/type_traits/is_array.hpp>
|
|
||||||
#include <boost/type_traits/is_pointer.hpp>
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/static_assert.hpp>
|
|
||||||
#include <boost/preprocessor/cat.hpp>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
|
|
||||||
struct error_cant_deduce_type {};
|
|
||||||
|
|
||||||
namespace type_deduction_detail
|
|
||||||
{
|
|
||||||
typedef char(&bool_value_type)[1];
|
|
||||||
typedef char(&int_value_type)[2];
|
|
||||||
typedef char(&uint_value_type)[3];
|
|
||||||
typedef char(&double_value_type)[4];
|
|
||||||
|
|
||||||
typedef char(&bool_reference_type)[5];
|
|
||||||
typedef char(&int_reference_type)[6];
|
|
||||||
typedef char(&uint_reference_type)[7];
|
|
||||||
typedef char(&double_reference_type)[8];
|
|
||||||
|
|
||||||
typedef char(&x_value_type)[9];
|
|
||||||
typedef char(&x_reference_type)[10];
|
|
||||||
typedef char(&x_const_pointer_type)[11];
|
|
||||||
typedef char(&x_pointer_type)[12];
|
|
||||||
|
|
||||||
typedef char(&y_value_type)[13];
|
|
||||||
typedef char(&y_reference_type)[14];
|
|
||||||
typedef char(&y_const_pointer_type)[15];
|
|
||||||
typedef char(&y_pointer_type)[16];
|
|
||||||
|
|
||||||
typedef char(&container_reference_type)[17];
|
|
||||||
typedef char(&container_const_reference_type)[18];
|
|
||||||
typedef char(&container_mapped_type)[19];
|
|
||||||
|
|
||||||
typedef char(&cant_deduce_type)[20];
|
|
||||||
|
|
||||||
template <typename T, typename PlainT = typename remove_cv<T>::type>
|
|
||||||
struct is_basic
|
|
||||||
: mpl::or_<
|
|
||||||
is_same<PlainT, bool>
|
|
||||||
, is_same<PlainT, int>
|
|
||||||
, is_same<PlainT, unsigned>
|
|
||||||
, is_same<PlainT, double>
|
|
||||||
> {};
|
|
||||||
|
|
||||||
template <typename C>
|
|
||||||
struct reference_type
|
|
||||||
{
|
|
||||||
typedef typename C::reference type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
|
||||||
struct reference_type<T[N]>
|
|
||||||
{
|
|
||||||
typedef T& type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct reference_type<T*>
|
|
||||||
{
|
|
||||||
typedef T& type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename C>
|
|
||||||
struct const_reference_type
|
|
||||||
{
|
|
||||||
typedef typename C::const_reference type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename C>
|
|
||||||
struct mapped_type
|
|
||||||
{
|
|
||||||
typedef typename C::mapped_type type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct asymmetric;
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
cant_deduce_type
|
|
||||||
test(...); // The black hole !!!
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
bool_value_type
|
|
||||||
test(bool const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
int_value_type
|
|
||||||
test(int const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
uint_value_type
|
|
||||||
test(unsigned const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
double_value_type
|
|
||||||
test(double const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
bool_reference_type
|
|
||||||
test(bool&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
int_reference_type
|
|
||||||
test(int&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
uint_reference_type
|
|
||||||
test(unsigned&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
double_reference_type
|
|
||||||
test(double&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
mpl::or_<is_basic<X>, is_const<X> >
|
|
||||||
, x_value_type
|
|
||||||
>::type
|
|
||||||
test(X const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
is_basic<X>
|
|
||||||
, x_reference_type
|
|
||||||
>::type
|
|
||||||
test(X&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
mpl::or_<
|
|
||||||
is_basic<X>
|
|
||||||
, is_const<X>
|
|
||||||
>
|
|
||||||
, x_const_pointer_type
|
|
||||||
>::type
|
|
||||||
test(X const*);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
x_pointer_type
|
|
||||||
test(X*);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
mpl::or_<
|
|
||||||
is_basic<Y>
|
|
||||||
, is_same<Y, asymmetric>
|
|
||||||
, is_const<Y>
|
|
||||||
, is_same<X, Y>
|
|
||||||
>
|
|
||||||
, y_value_type
|
|
||||||
>::type
|
|
||||||
test(Y const&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
mpl::or_<
|
|
||||||
is_basic<Y>
|
|
||||||
, is_same<Y, asymmetric>
|
|
||||||
, is_same<X, Y>
|
|
||||||
>
|
|
||||||
, y_reference_type
|
|
||||||
>::type
|
|
||||||
test(Y&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
mpl::or_<
|
|
||||||
is_same<Y, asymmetric>
|
|
||||||
, is_const<Y>
|
|
||||||
, is_same<X, Y>
|
|
||||||
>
|
|
||||||
, y_const_pointer_type
|
|
||||||
>::type
|
|
||||||
test(Y const*);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
mpl::or_<
|
|
||||||
is_same<Y, asymmetric>
|
|
||||||
, is_same<X, Y>
|
|
||||||
>
|
|
||||||
, y_pointer_type
|
|
||||||
>::type
|
|
||||||
test(Y*);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
is_basic<typename X::value_type>
|
|
||||||
, container_reference_type
|
|
||||||
>::type
|
|
||||||
test(typename X::reference);
|
|
||||||
|
|
||||||
template <typename X, typename Y, typename Z>
|
|
||||||
typename enable_if<
|
|
||||||
mpl::and_<
|
|
||||||
mpl::or_<is_array<X>, is_pointer<X> >
|
|
||||||
, mpl::not_<is_basic<Z> >
|
|
||||||
>
|
|
||||||
, container_reference_type
|
|
||||||
>::type
|
|
||||||
test(Z&);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
is_basic<typename X::value_type>
|
|
||||||
, container_const_reference_type
|
|
||||||
>::type
|
|
||||||
test(typename X::const_reference);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
typename disable_if<
|
|
||||||
is_basic<typename X::mapped_type>
|
|
||||||
, container_mapped_type
|
|
||||||
>::type
|
|
||||||
test(typename X::mapped_type);
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
struct base_result_of
|
|
||||||
{
|
|
||||||
typedef typename remove_reference<X>::type x_type;
|
|
||||||
typedef typename remove_reference<Y>::type y_type;
|
|
||||||
|
|
||||||
typedef mpl::vector20<
|
|
||||||
mpl::identity<bool>
|
|
||||||
, mpl::identity<int>
|
|
||||||
, mpl::identity<unsigned>
|
|
||||||
, mpl::identity<double>
|
|
||||||
, mpl::identity<bool&>
|
|
||||||
, mpl::identity<int&>
|
|
||||||
, mpl::identity<unsigned&>
|
|
||||||
, mpl::identity<double&>
|
|
||||||
, mpl::identity<x_type>
|
|
||||||
, mpl::identity<x_type&>
|
|
||||||
, mpl::identity<x_type const*>
|
|
||||||
, mpl::identity<x_type*>
|
|
||||||
, mpl::identity<y_type>
|
|
||||||
, mpl::identity<y_type&>
|
|
||||||
, mpl::identity<y_type const*>
|
|
||||||
, mpl::identity<y_type*>
|
|
||||||
, reference_type<x_type>
|
|
||||||
, const_reference_type<x_type>
|
|
||||||
, mapped_type<x_type>
|
|
||||||
, mpl::identity<error_cant_deduce_type>
|
|
||||||
>
|
|
||||||
types;
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace boost::type_deduction_detail
|
|
||||||
|
|
||||||
#define BOOST_RESULT_OF_COMMON(expr, name, Y, SYMMETRY) \
|
|
||||||
struct name \
|
|
||||||
{ \
|
|
||||||
typedef type_deduction_detail::base_result_of<X, Y> base_type; \
|
|
||||||
static typename base_type::x_type x; \
|
|
||||||
static typename base_type::y_type y; \
|
|
||||||
\
|
|
||||||
BOOST_STATIC_CONSTANT(int, \
|
|
||||||
size = sizeof( \
|
|
||||||
type_deduction_detail::test< \
|
|
||||||
typename base_type::x_type \
|
|
||||||
, SYMMETRY \
|
|
||||||
>(expr) \
|
|
||||||
)); \
|
|
||||||
\
|
|
||||||
BOOST_STATIC_CONSTANT(int, index = (size / sizeof(char)) - 1); \
|
|
||||||
\
|
|
||||||
typedef typename mpl::at_c< \
|
|
||||||
typename base_type::types, index>::type id; \
|
|
||||||
typedef typename id::type type; \
|
|
||||||
};
|
|
||||||
|
|
||||||
#define BOOST_UNARY_RESULT_OF(expr, name) \
|
|
||||||
template <typename X> \
|
|
||||||
BOOST_RESULT_OF_COMMON(expr, name, \
|
|
||||||
type_deduction_detail::asymmetric, type_deduction_detail::asymmetric)
|
|
||||||
|
|
||||||
#define BOOST_BINARY_RESULT_OF(expr, name) \
|
|
||||||
template <typename X, typename Y> \
|
|
||||||
BOOST_RESULT_OF_COMMON(expr, name, Y, typename base_type::y_type)
|
|
||||||
|
|
||||||
#define BOOST_ASYMMETRIC_BINARY_RESULT_OF(expr, name) \
|
|
||||||
template <typename X, typename Y> \
|
|
||||||
BOOST_RESULT_OF_COMMON(expr, name, Y, type_deduction_detail::asymmetric)
|
|
||||||
|
|
||||||
#endif
|
|
@@ -1,158 +0,0 @@
|
|||||||
#include <boost/ref.hpp>
|
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <vector>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
class generate_zero {
|
|
||||||
public:
|
|
||||||
typedef int result_type;
|
|
||||||
generate_zero() {}
|
|
||||||
int operator()() const { return 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
generate_zero(const generate_zero&);
|
|
||||||
};
|
|
||||||
|
|
||||||
class generate_zero_no_result_type {
|
|
||||||
public:
|
|
||||||
generate_zero_no_result_type() {}
|
|
||||||
int operator()() const { return 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
generate_zero_no_result_type(const generate_zero_no_result_type&);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void check_generate_zero(F f)
|
|
||||||
{
|
|
||||||
assert(f() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
class negate_with_result_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef int result_type;
|
|
||||||
|
|
||||||
negate_with_result_type() {}
|
|
||||||
int operator()(int x) const { return -x; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
negate_with_result_type(const negate_with_result_type&);
|
|
||||||
};
|
|
||||||
|
|
||||||
class negate_with_result_of
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<typename T>
|
|
||||||
struct result_of
|
|
||||||
{
|
|
||||||
typedef int type;
|
|
||||||
};
|
|
||||||
|
|
||||||
negate_with_result_of() {}
|
|
||||||
int operator()(int x) const { return -x; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
negate_with_result_of(const negate_with_result_of&);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void check_negate(F f)
|
|
||||||
{
|
|
||||||
int x = 5;
|
|
||||||
assert(f(x) == -x);
|
|
||||||
}
|
|
||||||
|
|
||||||
class add_with_result_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef int result_type;
|
|
||||||
|
|
||||||
add_with_result_type() {}
|
|
||||||
int operator()(int x, int y) const { return x + y; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
add_with_result_type(const add_with_result_type&);
|
|
||||||
};
|
|
||||||
|
|
||||||
class add_with_result_of
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<typename F> struct result_of { typedef int type; };
|
|
||||||
|
|
||||||
add_with_result_of() {}
|
|
||||||
int operator()(int x, int y) const { return x + y; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
add_with_result_of(const add_with_result_of&);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
void check_sum(F f)
|
|
||||||
{
|
|
||||||
int x = 3;
|
|
||||||
int y = 5;
|
|
||||||
assert(f(x, y) == x+y);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct zero_negate_add_result_type
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef int result_type;
|
|
||||||
|
|
||||||
zero_negate_add_result_type() {}
|
|
||||||
int operator()() const { return 0; }
|
|
||||||
int operator()(int x) const { return -x; }
|
|
||||||
int operator()(int x, int y) const { return x+y; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
zero_negate_add_result_type(const zero_negate_add_result_type&);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct zero_negate_add_result_of
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<typename F> struct result_of { typedef int type; };
|
|
||||||
|
|
||||||
zero_negate_add_result_of() {}
|
|
||||||
int operator()() const { return 0; }
|
|
||||||
int operator()(int x) const { return -x; }
|
|
||||||
int operator()(int x, int y) const { return x+y; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
zero_negate_add_result_of(const zero_negate_add_result_of&);
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Arity zero function objects
|
|
||||||
generate_zero gz;
|
|
||||||
generate_zero_no_result_type gznrt;
|
|
||||||
check_generate_zero(boost::ref(gz));
|
|
||||||
boost::ref(gznrt);
|
|
||||||
|
|
||||||
// Arity 1 function objects
|
|
||||||
negate_with_result_type nrt;
|
|
||||||
negate_with_result_of nro;
|
|
||||||
check_negate(boost::ref(nrt));
|
|
||||||
check_negate(boost::ref(nro));
|
|
||||||
|
|
||||||
// Arity 2 function objects
|
|
||||||
add_with_result_type art;
|
|
||||||
add_with_result_of aro;
|
|
||||||
check_sum(boost::ref(art));
|
|
||||||
check_sum(boost::ref(aro));
|
|
||||||
|
|
||||||
// Arity overloading in function objects
|
|
||||||
zero_negate_add_result_type znart;
|
|
||||||
zero_negate_add_result_type znaro;
|
|
||||||
check_generate_zero(boost::ref(znart));
|
|
||||||
check_negate(boost::ref(znart));
|
|
||||||
check_sum(boost::ref(znart));
|
|
||||||
check_generate_zero(boost::ref(znaro));
|
|
||||||
check_negate(boost::ref(znaro));
|
|
||||||
check_sum(boost::ref(znaro));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,35 +0,0 @@
|
|||||||
#include <boost/result_of.hpp>
|
|
||||||
#include <utility>
|
|
||||||
#include <boost/static_assert.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
|
|
||||||
class int_result_type { typedef int result_type; };
|
|
||||||
|
|
||||||
class int_result_of
|
|
||||||
{
|
|
||||||
template<typename F> struct result { typedef int type; };
|
|
||||||
};
|
|
||||||
|
|
||||||
class int_result_type_and_float_result_of
|
|
||||||
{
|
|
||||||
typedef int result_type;
|
|
||||||
template<typename F> struct result { typedef float type; };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct X {};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using namespace boost;
|
|
||||||
|
|
||||||
typedef int (*func_ptr)(float, double);
|
|
||||||
typedef int (X::*mem_func_ptr)(float);
|
|
||||||
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result_of<int_result_type(float)>::type, int>::value));
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result_of<int_result_of(double)>::type, int>::value));
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result_of<int_result_of(void)>::type, void>::value));
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result_of<int_result_type_and_float_result_of(char)>::type, int>::value));
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result_of<func_ptr(char, float)>::type, int>::value));
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result_of<mem_func_ptr(X,char)>::type, int>::value));
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,232 +0,0 @@
|
|||||||
<!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'><boost/utility/select_by_size.hpp></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_<0></SPAN>, <SPAN CLASS='code'>case_<1></SPAN>, <SPAN CLASS='code'>case_<2></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_<1></SPAN> and <SPAN CLASS='code'>case_<0></SPAN>. In some cases, <SPAN CLASS='code'>case_<true></SPAN> and <SPAN CLASS='code'>case_<false></SPAN> may be more suggestive. There is also a single return type representing a negative value: <SPAN CLASS='code'>case_<-1></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 <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);
|
|
||||||
};</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_<-1>, case_<0>, case_<1>, case_<2>, case_<3>, ...</PRE>
|
|
||||||
form a strictly increasing sequence. With well-behaved implementations, <SPAN CLASS='code'>sizeof(case_<-1>)</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_<N>) >::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_<N></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'><boost/utility/select_by_size.hpp></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<int N> struct <B>case_</B> { [<I>unspecified</I>] };
|
|
||||||
|
|
||||||
template<unsigned N>
|
|
||||||
struct <B>select_by_size</B> {
|
|
||||||
struct type {
|
|
||||||
static const unsigned value =
|
|
||||||
[M <I>such that</I> sizeof(case_<M>) == 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'><boost/mpl/aux_/template_arity.hpp></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'><boost/utility/type_deduction.hpp></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'><boost/outfmt/detail/type_traits.hpp></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_<-1>), sizeof(case_<0>), sizeof(case_<1>), sizeof(case_<2>), ... .</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_<-1>, case_<0>, case_<1>, ... </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'><boost/utility/select_by_size.hpp></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'><libs/utility/select_by_size_test.cpp></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'>
|
|
||||||
© 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>
|
|
@@ -1,60 +0,0 @@
|
|||||||
// (C) Copyright Jonathan Turkanis 2004.
|
|
||||||
// Permission to copy, use, modify, sell and distribute this software
|
|
||||||
// is granted provided this copyright notice appears in all copies. This
|
|
||||||
// software is provided "as is" without express or implied warranty, and
|
|
||||||
// with no claim as to its suitability for any purpose.
|
|
||||||
|
|
||||||
// Test program for <boost/utility/select_by_size.hpp>
|
|
||||||
|
|
||||||
#include <boost/static_assert.hpp>
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
// Include "select_by_size.hpp" with BOOST_SELECT_BY_SIZE_MAX_CASE undefined.
|
|
||||||
#include <boost/utility/select_by_size.hpp>
|
|
||||||
using boost::utility::case_;
|
|
||||||
|
|
||||||
case_<false> helper(bool);
|
|
||||||
case_<true> helper(int);
|
|
||||||
|
|
||||||
struct test1 {
|
|
||||||
// Define static bool constants v0 and v1.
|
|
||||||
BOOST_SELECT_BY_SIZE(bool, v0, helper(true));
|
|
||||||
BOOST_SELECT_BY_SIZE(bool, v1, helper(0));
|
|
||||||
|
|
||||||
BOOST_STATIC_ASSERT(v0 == false);
|
|
||||||
BOOST_STATIC_ASSERT(v1 == true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Include "select_by_size.hpp" a second time, defining more cases.
|
|
||||||
#define BOOST_SELECT_BY_SIZE_MAX_CASE 7
|
|
||||||
#include <boost/utility/select_by_size.hpp>
|
|
||||||
|
|
||||||
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 test2 {
|
|
||||||
// Define static int constants v0 through v7.
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v0, helper(true));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v1, helper(0));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v2, helper(0U));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v3, helper(0L));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v4, helper(0UL));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v5, helper(0.0F));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v6, helper(0.0));
|
|
||||||
BOOST_SELECT_BY_SIZE(int, v7, helper("hello"));
|
|
||||||
|
|
||||||
BOOST_STATIC_ASSERT(v0 == 0);
|
|
||||||
BOOST_STATIC_ASSERT(v1 == 1);
|
|
||||||
BOOST_STATIC_ASSERT(v2 == 2);
|
|
||||||
BOOST_STATIC_ASSERT(v3 == 3);
|
|
||||||
BOOST_STATIC_ASSERT(v4 == 4);
|
|
||||||
BOOST_STATIC_ASSERT(v5 == 5);
|
|
||||||
BOOST_STATIC_ASSERT(v6 == 6);
|
|
||||||
BOOST_STATIC_ASSERT(v7 == 7);
|
|
||||||
};
|
|
||||||
|
|
||||||
int main() { return 0; }
|
|
23
test/Jamfile
23
test/Jamfile
@@ -1,23 +0,0 @@
|
|||||||
# Boost Utility Library test Jamfile
|
|
||||||
|
|
||||||
subproject libs/utility/test ;
|
|
||||||
|
|
||||||
# bring in rules for testing
|
|
||||||
import testing ;
|
|
||||||
|
|
||||||
{
|
|
||||||
test-suite "utility"
|
|
||||||
: [ run lexicographic_test.cpp ]
|
|
||||||
[ run lex_performance_test.cpp ]
|
|
||||||
[ run named_params_test.cpp ]
|
|
||||||
[ run named_params_sfinae.cpp ]
|
|
||||||
[ run enable_if_constructors.cpp ]
|
|
||||||
[ run enable_if_member_templates.cpp ]
|
|
||||||
[ run enable_if_dummy_arg_disambiguation.cpp ]
|
|
||||||
[ run enable_if_namespace_disambiguation.cpp ]
|
|
||||||
[ run enable_if_lazy.cpp ]
|
|
||||||
[ run enable_if_no_disambiguation.cpp ]
|
|
||||||
[ run enable_if_lazy_test.cpp ]
|
|
||||||
[ run enable_if_partial_specializations.cpp ]
|
|
||||||
;
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
Boost Software License - Version 1.0 - August 17th, 2003
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person or organization
|
|
||||||
obtaining a copy of the software and accompanying documentation covered by
|
|
||||||
this license (the "Software") to use, reproduce, display, distribute,
|
|
||||||
execute, and transmit the Software, and to prepare derivative works of the
|
|
||||||
Software, and to permit third-parties to whom the Software is furnished to
|
|
||||||
do so, all subject to the following:
|
|
||||||
|
|
||||||
The copyright notices in the Software and this entire statement, including
|
|
||||||
the above license grant, this restriction and the following disclaimer,
|
|
||||||
must be included in all copies of the Software, in whole or in part, and
|
|
||||||
all derivative works of the Software, unless such copies or derivative
|
|
||||||
works are solely in the form of machine-executable object code generated by
|
|
||||||
a source language processor.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
||||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
||||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
@@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits.hpp>
|
|
||||||
|
|
||||||
using boost::enable_if;
|
|
||||||
using boost::disable_if;
|
|
||||||
using boost::is_arithmetic;
|
|
||||||
|
|
||||||
struct container {
|
|
||||||
bool my_value;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
container(const T&, const typename enable_if<is_arithmetic<T>, T>::type * = 0):
|
|
||||||
my_value(true) {}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
container(const T&, const typename disable_if<is_arithmetic<T>, T>::type * = 0):
|
|
||||||
my_value(false) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// example from Howard Hinnant (tests enable_if template members of a templated class)
|
|
||||||
template <class charT>
|
|
||||||
struct xstring
|
|
||||||
{
|
|
||||||
template <class It>
|
|
||||||
xstring(It begin, It end, typename
|
|
||||||
disable_if<is_arithmetic<It> >::type* = 0)
|
|
||||||
: data(end-begin) {}
|
|
||||||
|
|
||||||
int data;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
|
|
||||||
BOOST_CHECK(container(1).my_value);
|
|
||||||
BOOST_CHECK(container(1.0).my_value);
|
|
||||||
|
|
||||||
BOOST_CHECK(!container("1").my_value);
|
|
||||||
BOOST_CHECK(!container(static_cast<void*>(0)).my_value);
|
|
||||||
|
|
||||||
char sa[] = "123456";
|
|
||||||
BOOST_CHECK(xstring<char>(sa, sa+6).data == 6);
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,44 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_arithmetic.hpp>
|
|
||||||
|
|
||||||
using boost::enable_if;
|
|
||||||
using boost::disable_if;
|
|
||||||
using boost::is_arithmetic;
|
|
||||||
|
|
||||||
template <int N> struct dummy {
|
|
||||||
dummy(int) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename enable_if<is_arithmetic<T>, bool>::type
|
|
||||||
arithmetic_object(T t, dummy<0> = 0) { return true; }
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename disable_if<is_arithmetic<T>, bool>::type
|
|
||||||
arithmetic_object(T t, dummy<1> = 0) { return false; }
|
|
||||||
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
|
|
||||||
BOOST_CHECK(arithmetic_object(1));
|
|
||||||
BOOST_CHECK(arithmetic_object(1.0));
|
|
||||||
|
|
||||||
BOOST_CHECK(!arithmetic_object("1"));
|
|
||||||
BOOST_CHECK(!arithmetic_object(static_cast<void*>(0)));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,80 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
|
|
||||||
using boost::enable_if_c;
|
|
||||||
using boost::lazy_enable_if_c;
|
|
||||||
|
|
||||||
// This class provides a reduced example of a traits class for
|
|
||||||
// computing the result of multiplying two types. The member typedef
|
|
||||||
// 'type' in this traits class defines the return type of this
|
|
||||||
// operator. The return type member is invalid unless both arguments
|
|
||||||
// for mult_traits are values that mult_traits expects (ints in this
|
|
||||||
// case). This kind of situation may arise if a traits class only
|
|
||||||
// makes sense for some set of types, not all C++ types.
|
|
||||||
|
|
||||||
template <class T> struct is_int {
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = (boost::is_same<T, int>::value));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class U>
|
|
||||||
struct mult_traits {
|
|
||||||
typedef typename T::does_not_exist type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct mult_traits<int, int> {
|
|
||||||
typedef int type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Next, a forwarding function mult() is defined. It is enabled only
|
|
||||||
// when both arguments are of type int. The first version, using
|
|
||||||
// non-lazy enable_if_c does not work.
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
template <class T, class U>
|
|
||||||
typename enable_if_c<
|
|
||||||
is_int<T>::value && is_int<U>::value,
|
|
||||||
typename mult_traits<T, U>::type
|
|
||||||
>::type
|
|
||||||
mult(const T& x, const U& y) {return x * y;}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// A correct version uses lazy_enable_if_c.
|
|
||||||
// This template removes compiler errors from invalid code used as an
|
|
||||||
// argument to enable_if_c.
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
template <class T, class U>
|
|
||||||
typename lazy_enable_if_c<
|
|
||||||
is_int<T>::value && is_int<U>::value,
|
|
||||||
mult_traits<T, U>
|
|
||||||
>::type
|
|
||||||
mult(const T& x, const U& y) {return x * y;}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
double mult(int i, double d) { return (double)i * d; }
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
BOOST_CHECK(mult(1, 2) == 2);
|
|
||||||
|
|
||||||
BOOST_CHECK(mult(1, 3.0) == 3.0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,98 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
// Testing all variations of lazy_enable_if.
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
#include <boost/mpl/not.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
|
|
||||||
using boost::lazy_enable_if;
|
|
||||||
using boost::lazy_disable_if;
|
|
||||||
|
|
||||||
using boost::lazy_enable_if_c;
|
|
||||||
using boost::lazy_disable_if_c;
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct is_int_or_double {
|
|
||||||
BOOST_STATIC_CONSTANT(bool,
|
|
||||||
value = (boost::is_same<T, int>::value ||
|
|
||||||
boost::is_same<T, double>::value));
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct some_traits {
|
|
||||||
typedef typename T::does_not_exist type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct some_traits<int> {
|
|
||||||
typedef bool type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct some_traits<double> {
|
|
||||||
typedef bool type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct make_bool {
|
|
||||||
typedef bool type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct make_bool<int> {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct make_bool<double> {};
|
|
||||||
|
|
||||||
namespace A {
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename lazy_enable_if<is_int_or_double<T>, some_traits<T> >::type
|
|
||||||
foo(T t) { return true; }
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename lazy_enable_if_c<is_int_or_double<T>::value, some_traits<T> >::type
|
|
||||||
foo2(T t) { return true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace B {
|
|
||||||
template<class T>
|
|
||||||
typename lazy_disable_if<is_int_or_double<T>, make_bool<T> >::type
|
|
||||||
foo(T t) { return false; }
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename lazy_disable_if_c<is_int_or_double<T>::value, make_bool<T> >::type
|
|
||||||
foo2(T t) { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
using namespace A;
|
|
||||||
using namespace B;
|
|
||||||
BOOST_CHECK(foo(1));
|
|
||||||
BOOST_CHECK(foo(1.0));
|
|
||||||
|
|
||||||
BOOST_CHECK(!foo("1"));
|
|
||||||
BOOST_CHECK(!foo(static_cast<void*>(0)));
|
|
||||||
|
|
||||||
BOOST_CHECK(foo2(1));
|
|
||||||
BOOST_CHECK(foo2(1.0));
|
|
||||||
|
|
||||||
BOOST_CHECK(!foo2("1"));
|
|
||||||
BOOST_CHECK(!foo2(static_cast<void*>(0)));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_arithmetic.hpp>
|
|
||||||
|
|
||||||
using boost::enable_if;
|
|
||||||
using boost::disable_if;
|
|
||||||
using boost::is_arithmetic;
|
|
||||||
|
|
||||||
struct container {
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<is_arithmetic<T>, bool>::type
|
|
||||||
arithmetic_object(const T&, const int* /* disambiguate */ = 0) {return true;}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<is_arithmetic<T>, bool>::type
|
|
||||||
arithmetic_object(const T&) {return false;}
|
|
||||||
};
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
|
|
||||||
BOOST_CHECK(container().arithmetic_object(1));
|
|
||||||
BOOST_CHECK(container().arithmetic_object(1.0));
|
|
||||||
|
|
||||||
BOOST_CHECK(!container().arithmetic_object("1"));
|
|
||||||
BOOST_CHECK(!container().arithmetic_object(static_cast<void*>(0)));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,45 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
#include <boost/mpl/not.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_arithmetic.hpp>
|
|
||||||
|
|
||||||
using boost::enable_if;
|
|
||||||
using boost::mpl::not_;
|
|
||||||
using boost::is_arithmetic;
|
|
||||||
|
|
||||||
namespace A {
|
|
||||||
template<class T>
|
|
||||||
typename enable_if<is_arithmetic<T>, bool>::type
|
|
||||||
arithmetic_object(T t) { return true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace B {
|
|
||||||
template<class T>
|
|
||||||
typename enable_if<not_<is_arithmetic<T> >, bool>::type
|
|
||||||
arithmetic_object(T t) { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
using namespace A;
|
|
||||||
using namespace B;
|
|
||||||
BOOST_CHECK(arithmetic_object(1));
|
|
||||||
BOOST_CHECK(arithmetic_object(1.0));
|
|
||||||
|
|
||||||
BOOST_CHECK(!arithmetic_object("1"));
|
|
||||||
BOOST_CHECK(!arithmetic_object(static_cast<void*>(0)));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
#include <boost/mpl/not.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_arithmetic.hpp>
|
|
||||||
|
|
||||||
using boost::mpl::not_;
|
|
||||||
using boost::enable_if;
|
|
||||||
using boost::is_arithmetic;
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename enable_if<is_arithmetic<T>, bool>::type
|
|
||||||
arithmetic_object(T t) { return true; }
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
typename enable_if<not_<is_arithmetic<T> >, bool>::type
|
|
||||||
arithmetic_object(T t) { return false; }
|
|
||||||
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
|
|
||||||
BOOST_CHECK(arithmetic_object(1));
|
|
||||||
BOOST_CHECK(arithmetic_object(1.0));
|
|
||||||
|
|
||||||
BOOST_CHECK(!arithmetic_object("1"));
|
|
||||||
BOOST_CHECK(!arithmetic_object(static_cast<void*>(0)));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,65 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright 2003 <20> The Trustees of Indiana University.
|
|
||||||
//
|
|
||||||
// See the file enable_if_LICENSE for licensing conditions.
|
|
||||||
//
|
|
||||||
// Authors: Jaakko J<>rvi (jajarvi at osl.iu.edu)
|
|
||||||
// Jeremiah Willcock (jewillco at osl.iu.edu)
|
|
||||||
// Andrew Lumsdaine (lums at osl.iu.edu)
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/type_traits/is_arithmetic.hpp>
|
|
||||||
|
|
||||||
using boost::enable_if_c;
|
|
||||||
using boost::disable_if_c;
|
|
||||||
using boost::enable_if;
|
|
||||||
using boost::disable_if;
|
|
||||||
using boost::is_arithmetic;
|
|
||||||
|
|
||||||
template <class T, class Enable = void>
|
|
||||||
struct tester;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct tester<T, typename enable_if_c<is_arithmetic<T>::value>::type> {
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct tester<T, typename disable_if_c<is_arithmetic<T>::value>::type> {
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class Enable = void>
|
|
||||||
struct tester2;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct tester2<T, typename enable_if<is_arithmetic<T> >::type> {
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct tester2<T, typename disable_if<is_arithmetic<T> >::type> {
|
|
||||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
int test_main(int, char*[])
|
|
||||||
{
|
|
||||||
|
|
||||||
BOOST_CHECK(tester<int>::value);
|
|
||||||
BOOST_CHECK(tester<double>::value);
|
|
||||||
|
|
||||||
BOOST_CHECK(!tester<char*>::value);
|
|
||||||
BOOST_CHECK(!tester<void*>::value);
|
|
||||||
|
|
||||||
BOOST_CHECK(tester2<int>::value);
|
|
||||||
BOOST_CHECK(tester2<double>::value);
|
|
||||||
|
|
||||||
BOOST_CHECK(!tester2<char*>::value);
|
|
||||||
BOOST_CHECK(!tester2<void*>::value);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,135 +0,0 @@
|
|||||||
// Copyright (c) 2003 Jan Langer
|
|
||||||
// Use, modification, and distribution is subject to 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)
|
|
||||||
|
|
||||||
// See library home page at http://www.boost.org/libs/utility
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <boost/utility/lexicographic.hpp>
|
|
||||||
#include <boost/timer.hpp>
|
|
||||||
|
|
||||||
bool cmp_lex (int a, int b)
|
|
||||||
{
|
|
||||||
return boost::lexicographic
|
|
||||||
(a / 1000, b / 1000)
|
|
||||||
(b / 100, a / 100)
|
|
||||||
(a / 10, b / 10)
|
|
||||||
(b, a);
|
|
||||||
}
|
|
||||||
bool cmp_lex_nl (int a, int b)
|
|
||||||
{
|
|
||||||
return boost::lexicographic
|
|
||||||
(a, b)
|
|
||||||
(b, a)
|
|
||||||
(a, b)
|
|
||||||
(b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cmp_emul_nl (int a, int b)
|
|
||||||
{
|
|
||||||
typedef boost::lexicographic::result_type result_type;
|
|
||||||
result_type const equivalent = boost::lexicographic::equivalent;
|
|
||||||
result_type const minus = boost::lexicographic::minus;
|
|
||||||
result_type const plus = boost::lexicographic::plus;
|
|
||||||
|
|
||||||
// ctor
|
|
||||||
result_type m = equivalent;
|
|
||||||
if (a < b)
|
|
||||||
m = minus;
|
|
||||||
else if (b < a)
|
|
||||||
m = plus;
|
|
||||||
else
|
|
||||||
m = equivalent;
|
|
||||||
|
|
||||||
// first operator ()
|
|
||||||
if (m == equivalent)
|
|
||||||
if (b < a)
|
|
||||||
m = minus;
|
|
||||||
else if (a < b)
|
|
||||||
m = plus;
|
|
||||||
else
|
|
||||||
m = equivalent;
|
|
||||||
|
|
||||||
// second operator ()
|
|
||||||
if (m == equivalent)
|
|
||||||
if (a < b)
|
|
||||||
m = minus;
|
|
||||||
else if (b < a)
|
|
||||||
m = plus;
|
|
||||||
else
|
|
||||||
m = equivalent;
|
|
||||||
|
|
||||||
// third operator ()
|
|
||||||
if (m == equivalent)
|
|
||||||
if (b < a)
|
|
||||||
m = minus;
|
|
||||||
else if (a < b)
|
|
||||||
m = plus;
|
|
||||||
else
|
|
||||||
m = equivalent;
|
|
||||||
|
|
||||||
return m == minus;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cmp_cascade (int a, int b)
|
|
||||||
{
|
|
||||||
if (a / 1000 == b / 1000)
|
|
||||||
if (b / 100 == a / 100)
|
|
||||||
if (a / 10 == b / 10)
|
|
||||||
return b < a;
|
|
||||||
else
|
|
||||||
return a / 10 < b / 10;
|
|
||||||
else
|
|
||||||
return b / 100 < a / 100;
|
|
||||||
else
|
|
||||||
return a / 1000 < b / 1000;
|
|
||||||
}
|
|
||||||
bool cmp_cascade_nl (int a, int b)
|
|
||||||
{
|
|
||||||
if (a == b)
|
|
||||||
if (b == a)
|
|
||||||
if (a == b)
|
|
||||||
return b < a;
|
|
||||||
else
|
|
||||||
return a < b;
|
|
||||||
else
|
|
||||||
return b < a;
|
|
||||||
else
|
|
||||||
return a < b;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::vector <int> int_vector;
|
|
||||||
|
|
||||||
void run (int_vector values, // make copy to keep original random order
|
|
||||||
bool (*cmp) (int, int),
|
|
||||||
std::string desc)
|
|
||||||
{
|
|
||||||
boost::timer uhr;
|
|
||||||
std::sort (values.begin (), values.end (), cmp);
|
|
||||||
std::cout << desc << " - " << uhr.elapsed() << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
int main ()
|
|
||||||
{
|
|
||||||
int_vector::size_type const n = 400000;
|
|
||||||
int_vector values;
|
|
||||||
values.reserve (n);
|
|
||||||
|
|
||||||
std::srand (std::time (0));
|
|
||||||
for (unsigned int i = 0; i < n; ++i)
|
|
||||||
values.push_back (std::rand ());
|
|
||||||
|
|
||||||
run (values, cmp_lex, "boost::lexicographic, division");
|
|
||||||
run (values, cmp_lex_nl, "boost::lexicographic, no division");
|
|
||||||
run (values, cmp_emul_nl, "boost::lexicographic emulation, no division");
|
|
||||||
run (values, cmp_cascade, "if cascade, division");
|
|
||||||
run (values, cmp_cascade_nl, "if cascade, no division");
|
|
||||||
}
|
|
||||||
|
|
@@ -1,74 +0,0 @@
|
|||||||
// Copyright (c) 2003 Jan Langer
|
|
||||||
// Use, modification, and distribution is subject to 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)
|
|
||||||
|
|
||||||
// See library home page at http://www.boost.org/libs/utility
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
#include <boost/utility/lexicographic.hpp>
|
|
||||||
|
|
||||||
int test_main (int, char *[])
|
|
||||||
{
|
|
||||||
using boost::lexicographic;
|
|
||||||
|
|
||||||
lexicographic l1; // equivalent
|
|
||||||
BOOST_CHECK (!l1);
|
|
||||||
|
|
||||||
lexicographic l2 (l1); // equivalent
|
|
||||||
BOOST_CHECK (!l2);
|
|
||||||
BOOST_CHECK (l1 == l2);
|
|
||||||
|
|
||||||
l2 = l1;
|
|
||||||
BOOST_CHECK (!l2);
|
|
||||||
BOOST_CHECK (l2 == l1);
|
|
||||||
|
|
||||||
l2 (3, 6); // less
|
|
||||||
BOOST_CHECK (l2);
|
|
||||||
BOOST_CHECK (l2.result () == lexicographic::minus);
|
|
||||||
BOOST_CHECK (lexicographic::minus == l2.result ());
|
|
||||||
BOOST_CHECK (l2.result () != lexicographic::equivalent);
|
|
||||||
BOOST_CHECK (lexicographic::equivalent != l2.result ());
|
|
||||||
BOOST_CHECK (l1 != l2);
|
|
||||||
|
|
||||||
lexicographic l3 (3.0, 1.0); // greater
|
|
||||||
BOOST_CHECK (!l3);
|
|
||||||
BOOST_CHECK (l3 != l1);
|
|
||||||
|
|
||||||
for (int i = 1; i <= 3; ++i)
|
|
||||||
for (int j = 1; j <= 3; ++j)
|
|
||||||
for (int k = 1; k <= 3; ++k)
|
|
||||||
{
|
|
||||||
lexicographic l4;
|
|
||||||
l4 (i, 2) (j, 2) (k, 2);
|
|
||||||
|
|
||||||
if (i < 2)
|
|
||||||
BOOST_CHECK (l4);
|
|
||||||
else if (i > 2)
|
|
||||||
BOOST_CHECK (!l4);
|
|
||||||
else if (j < 2)
|
|
||||||
BOOST_CHECK (l4);
|
|
||||||
else if (j > 2)
|
|
||||||
BOOST_CHECK (!l4);
|
|
||||||
else if (k < 2)
|
|
||||||
BOOST_CHECK (l4);
|
|
||||||
else
|
|
||||||
BOOST_CHECK (!l4);
|
|
||||||
}
|
|
||||||
|
|
||||||
lexicographic l5;
|
|
||||||
l5 (1, 1, std::greater <int> ()) (2, 3);
|
|
||||||
BOOST_CHECK (l5);
|
|
||||||
|
|
||||||
lexicographic l6;
|
|
||||||
l6 (1, 1, std::greater <int> ()) (2, 3, std::greater <int> ());
|
|
||||||
BOOST_CHECK (!l6);
|
|
||||||
|
|
||||||
lexicographic l7;
|
|
||||||
l7 (1, 1) (2, 3, std::greater <int> ());
|
|
||||||
BOOST_CHECK (!l7);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,79 +0,0 @@
|
|||||||
// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and
|
|
||||||
// distribution is subject to 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
|
|
||||||
|
|
||||||
#include <boost/named_params.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <string>
|
|
||||||
#include <boost/type_traits/is_convertible.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace test
|
|
||||||
{
|
|
||||||
using boost::keyword;
|
|
||||||
using boost::keywords;
|
|
||||||
using boost::named_param;
|
|
||||||
|
|
||||||
struct name_t; keyword<name_t> name;
|
|
||||||
struct value_t; keyword<value_t> value;
|
|
||||||
|
|
||||||
struct f_keywords
|
|
||||||
: keywords<
|
|
||||||
named_param<
|
|
||||||
name_t
|
|
||||||
, boost::mpl::true_
|
|
||||||
, boost::is_convertible<boost::mpl::_, std::string>
|
|
||||||
>
|
|
||||||
, named_param<
|
|
||||||
value_t
|
|
||||||
, boost::mpl::true_
|
|
||||||
, boost::is_convertible<boost::mpl::_, float>
|
|
||||||
>
|
|
||||||
>
|
|
||||||
{};
|
|
||||||
|
|
||||||
template<class P>
|
|
||||||
void f_impl(P const& p)
|
|
||||||
{
|
|
||||||
std::string s = p[name | "bar"];
|
|
||||||
float v = p[value | 3.f];
|
|
||||||
|
|
||||||
assert(s == "foo");
|
|
||||||
assert(v == 3.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void f()
|
|
||||||
{
|
|
||||||
f_impl(f_keywords()());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0>
|
|
||||||
void f(A0 const& a0
|
|
||||||
, typename f_keywords::restrict<A0>::type = f_keywords())
|
|
||||||
{
|
|
||||||
f_impl(f_keywords()(a0));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class A0, class A1>
|
|
||||||
void f(A0 const& a0, A1 const& a1
|
|
||||||
, typename f_keywords::restrict<A0, A1>::type = f_keywords())
|
|
||||||
{
|
|
||||||
f_impl(f_keywords()(a0, a1));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using test::name;
|
|
||||||
using test::value;
|
|
||||||
using test::f;
|
|
||||||
|
|
||||||
f("foo");
|
|
||||||
f("foo", 3.f);
|
|
||||||
f(value = 3.f, name = "foo");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,156 +0,0 @@
|
|||||||
// Copyright David Abrahams, Daniel Wallin 2003. Use, modification and
|
|
||||||
// distribution is subject to 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)
|
|
||||||
|
|
||||||
#include <boost/named_params.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <string.h>
|
|
||||||
#include <boost/bind.hpp>
|
|
||||||
#include <boost/ref.hpp>
|
|
||||||
|
|
||||||
namespace test
|
|
||||||
{
|
|
||||||
|
|
||||||
using boost::keyword;
|
|
||||||
using boost::keywords;
|
|
||||||
using boost::named_param;
|
|
||||||
|
|
||||||
struct name_t;
|
|
||||||
keyword<name_t> name;
|
|
||||||
|
|
||||||
struct value_t;
|
|
||||||
keyword <value_t> value;
|
|
||||||
|
|
||||||
struct index_t;
|
|
||||||
keyword<index_t> index;
|
|
||||||
|
|
||||||
struct tester_t;
|
|
||||||
keyword<tester_t> tester;
|
|
||||||
|
|
||||||
struct f_keywords // vc6 is happier with inheritance than with a typedef
|
|
||||||
: keywords<
|
|
||||||
tester_t
|
|
||||||
, name_t
|
|
||||||
, value_t
|
|
||||||
, index_t
|
|
||||||
>
|
|
||||||
{};
|
|
||||||
|
|
||||||
double value_default()
|
|
||||||
{
|
|
||||||
return 666.222;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Params>
|
|
||||||
int f_impl(const Params& p)
|
|
||||||
{
|
|
||||||
p[tester](
|
|
||||||
p[name]
|
|
||||||
, p[value || boost::bind(&value_default) ]
|
|
||||||
, p[index | 999]
|
|
||||||
);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Tester, class Name, class Value, class Index>
|
|
||||||
int f(Tester const& t, const Name& name_,
|
|
||||||
const Value& value_, const Index& index_)
|
|
||||||
{
|
|
||||||
return f_impl(f_keywords()(t, name_, value_, index_));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Tester, class Name, class Value>
|
|
||||||
int f(Tester const& t, const Name& name_, const Value& value_)
|
|
||||||
{
|
|
||||||
return f_impl(f_keywords()(t, name_, value_));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Tester, class Name>
|
|
||||||
int f(Tester const& t, const Name& name_)
|
|
||||||
{
|
|
||||||
return f_impl(f_keywords()(t, name_));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
bool equal(T const& x, T const& y)
|
|
||||||
{
|
|
||||||
return x == y;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool equal(char const* s1, char const* s2)
|
|
||||||
{
|
|
||||||
return !strcmp(s1,s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Name, class Value, class Index>
|
|
||||||
struct values_t
|
|
||||||
{
|
|
||||||
values_t(Name const& n, Value const& v, Index const& i)
|
|
||||||
: n(n), v(v), i(i)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template <class Name_, class Value_, class Index_>
|
|
||||||
void operator()(Name_ const& n_, Value_ const& v_, Index_ const& i_) const
|
|
||||||
{
|
|
||||||
|
|
||||||
// Only VC and its emulators fail this; they seem to have
|
|
||||||
// problems with deducing the constness of string literal
|
|
||||||
// arrays.
|
|
||||||
#if defined(_MSC_VER) \
|
|
||||||
&& (BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION, <= 700) \
|
|
||||||
|| BOOST_WORKAROUND(BOOST_MSVC, < 1310))
|
|
||||||
# else
|
|
||||||
BOOST_STATIC_ASSERT((boost::is_same<Index,Index_>::value));
|
|
||||||
BOOST_STATIC_ASSERT((boost::is_same<Value,Value_>::value));
|
|
||||||
BOOST_STATIC_ASSERT((boost::is_same<Name,Name_>::value));
|
|
||||||
#endif
|
|
||||||
assert(equal(n, n_));
|
|
||||||
assert(equal(v, v_));
|
|
||||||
assert(equal(i, i_));
|
|
||||||
}
|
|
||||||
|
|
||||||
Name const& n;
|
|
||||||
Value const& v;
|
|
||||||
Index const& i;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Name, class Value, class Index>
|
|
||||||
values_t<Name,Value,Index>
|
|
||||||
values(Name const& n, Value const& v, Index const& i)
|
|
||||||
{
|
|
||||||
return values_t<Name,Value,Index>(n,v,i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GCC2 has a problem with char (&)[] deduction, so we'll cast string
|
|
||||||
// literals there.
|
|
||||||
#undef S
|
|
||||||
#if BOOST_WORKAROUND(__GNUC__, == 2)
|
|
||||||
# define S(s) (char const*)s
|
|
||||||
#else
|
|
||||||
# define S(s) s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using test::f;
|
|
||||||
using test::name;
|
|
||||||
using test::value;
|
|
||||||
using test::index;
|
|
||||||
using test::tester;
|
|
||||||
|
|
||||||
f(
|
|
||||||
test::values(S("foo"), S("bar"), S("baz"))
|
|
||||||
, S("foo"), S("bar"), S("baz")
|
|
||||||
);
|
|
||||||
|
|
||||||
int x = 56;
|
|
||||||
f(
|
|
||||||
test::values("foo", 666.222, 56)
|
|
||||||
, index = boost::ref(x), name = "foo"
|
|
||||||
);
|
|
||||||
|
|
||||||
//f(index = 56, name = 55); // won't compile
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,129 +0,0 @@
|
|||||||
// Copyright (C) 2002-2003 Doug Gregor (gregod@cs.rpi.edu)
|
|
||||||
//
|
|
||||||
// Permission to copy, use, sell and distribute this software is granted
|
|
||||||
// provided this copyright notice appears in all copies.
|
|
||||||
// Permission to modify the code and to distribute modified code is granted
|
|
||||||
// provided this copyright notice appears in all copies, and a notice
|
|
||||||
// that the code was modified is included with the copyright notice.
|
|
||||||
//
|
|
||||||
// This software is provided "as is" without express or implied warranty,
|
|
||||||
// and with no claim as to its suitability for any purpose.
|
|
||||||
|
|
||||||
// For more information, see http://www.boost.org
|
|
||||||
|
|
||||||
#include <boost/tribool.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
BOOST_TRIBOOL_THIRD_STATE(maybe)
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using namespace boost;
|
|
||||||
|
|
||||||
tribool x; // false
|
|
||||||
tribool y(true); // true
|
|
||||||
tribool z(maybe); // maybe
|
|
||||||
|
|
||||||
assert(!x);
|
|
||||||
assert(x == false);
|
|
||||||
assert(false == x);
|
|
||||||
assert(x != true);
|
|
||||||
assert(true != x);
|
|
||||||
assert(maybe(x == maybe));
|
|
||||||
assert(maybe(maybe == x));
|
|
||||||
assert(maybe(x != maybe));
|
|
||||||
assert(maybe(maybe != x));
|
|
||||||
assert(x == x);
|
|
||||||
assert(!(x != x));
|
|
||||||
assert(!(x && true));
|
|
||||||
assert(!(true && x));
|
|
||||||
assert(x || true);
|
|
||||||
assert(true || x);
|
|
||||||
|
|
||||||
assert(y);
|
|
||||||
assert(y == true);
|
|
||||||
assert(true == y);
|
|
||||||
assert(y != false);
|
|
||||||
assert(false != y);
|
|
||||||
assert(maybe(y == maybe));
|
|
||||||
assert(maybe(maybe == y));
|
|
||||||
assert(maybe(y != maybe));
|
|
||||||
assert(maybe(maybe != y));
|
|
||||||
assert(y == y);
|
|
||||||
assert(!(y != y));
|
|
||||||
|
|
||||||
assert(maybe(z || !z));
|
|
||||||
assert(maybe(z == true));
|
|
||||||
assert(maybe(true == z));
|
|
||||||
assert(maybe(z == false));
|
|
||||||
assert(maybe(false == z));
|
|
||||||
assert(maybe(z == maybe));
|
|
||||||
assert(maybe(maybe == z));
|
|
||||||
assert(maybe(z != maybe));
|
|
||||||
assert(maybe(maybe != z));
|
|
||||||
assert(maybe(z == z));
|
|
||||||
assert(maybe(z != z));
|
|
||||||
|
|
||||||
assert(!(x == y));
|
|
||||||
assert(x != y);
|
|
||||||
assert(maybe(x == z));
|
|
||||||
assert(maybe(x != z));
|
|
||||||
assert(maybe(y == z));
|
|
||||||
assert(maybe(y != z));
|
|
||||||
|
|
||||||
assert(!(x && y));
|
|
||||||
assert(x || y);
|
|
||||||
assert(!(x && z));
|
|
||||||
assert(maybe(y && z));
|
|
||||||
assert(maybe(z && z));
|
|
||||||
assert(maybe(z || z));
|
|
||||||
assert(maybe(x || z));
|
|
||||||
assert(y || z);
|
|
||||||
|
|
||||||
assert(maybe(y && maybe));
|
|
||||||
assert(maybe(maybe && y));
|
|
||||||
assert(!(x && maybe));
|
|
||||||
assert(!(maybe && x));
|
|
||||||
|
|
||||||
assert(maybe || y);
|
|
||||||
assert(y || maybe);
|
|
||||||
assert(maybe(x || maybe));
|
|
||||||
assert(maybe(maybe || x));
|
|
||||||
|
|
||||||
// Test the if (z) ... else (!z) ... else ... idiom
|
|
||||||
if (z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else if (!z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
z = true;
|
|
||||||
if (z) {
|
|
||||||
assert(true);
|
|
||||||
}
|
|
||||||
else if (!z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
z = false;
|
|
||||||
if (z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else if (!z) {
|
|
||||||
assert(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "no errors detected\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,127 +0,0 @@
|
|||||||
// Copyright (C) 2002-2003 Doug Gregor (gregod@cs.rpi.edu)
|
|
||||||
//
|
|
||||||
// Permission to copy, use, sell and distribute this software is granted
|
|
||||||
// provided this copyright notice appears in all copies.
|
|
||||||
// Permission to modify the code and to distribute modified code is granted
|
|
||||||
// provided this copyright notice appears in all copies, and a notice
|
|
||||||
// that the code was modified is included with the copyright notice.
|
|
||||||
//
|
|
||||||
// This software is provided "as is" without express or implied warranty,
|
|
||||||
// and with no claim as to its suitability for any purpose.
|
|
||||||
|
|
||||||
// For more information, see http://www.boost.org
|
|
||||||
|
|
||||||
#include <boost/tribool.hpp>
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
using namespace boost;
|
|
||||||
|
|
||||||
tribool x; // false
|
|
||||||
tribool y(true); // true
|
|
||||||
tribool z(indeterminate); // indeterminate
|
|
||||||
|
|
||||||
assert(!x);
|
|
||||||
assert(x == false);
|
|
||||||
assert(false == x);
|
|
||||||
assert(x != true);
|
|
||||||
assert(true != x);
|
|
||||||
assert(indeterminate(x == indeterminate));
|
|
||||||
assert(indeterminate(indeterminate == x));
|
|
||||||
assert(indeterminate(x != indeterminate));
|
|
||||||
assert(indeterminate(indeterminate != x));
|
|
||||||
assert(x == x);
|
|
||||||
assert(!(x != x));
|
|
||||||
assert(!(x && true));
|
|
||||||
assert(!(true && x));
|
|
||||||
assert(x || true);
|
|
||||||
assert(true || x);
|
|
||||||
|
|
||||||
assert(y);
|
|
||||||
assert(y == true);
|
|
||||||
assert(true == y);
|
|
||||||
assert(y != false);
|
|
||||||
assert(false != y);
|
|
||||||
assert(indeterminate(y == indeterminate));
|
|
||||||
assert(indeterminate(indeterminate == y));
|
|
||||||
assert(indeterminate(y != indeterminate));
|
|
||||||
assert(indeterminate(indeterminate != y));
|
|
||||||
assert(y == y);
|
|
||||||
assert(!(y != y));
|
|
||||||
|
|
||||||
assert(indeterminate(z || !z));
|
|
||||||
assert(indeterminate(z == true));
|
|
||||||
assert(indeterminate(true == z));
|
|
||||||
assert(indeterminate(z == false));
|
|
||||||
assert(indeterminate(false == z));
|
|
||||||
assert(indeterminate(z == indeterminate));
|
|
||||||
assert(indeterminate(indeterminate == z));
|
|
||||||
assert(indeterminate(z != indeterminate));
|
|
||||||
assert(indeterminate(indeterminate != z));
|
|
||||||
assert(indeterminate(z == z));
|
|
||||||
assert(indeterminate(z != z));
|
|
||||||
|
|
||||||
assert(!(x == y));
|
|
||||||
assert(x != y);
|
|
||||||
assert(indeterminate(x == z));
|
|
||||||
assert(indeterminate(x != z));
|
|
||||||
assert(indeterminate(y == z));
|
|
||||||
assert(indeterminate(y != z));
|
|
||||||
|
|
||||||
assert(!(x && y));
|
|
||||||
assert(x || y);
|
|
||||||
assert(!(x && z));
|
|
||||||
assert(indeterminate(y && z));
|
|
||||||
assert(indeterminate(z && z));
|
|
||||||
assert(indeterminate(z || z));
|
|
||||||
assert(indeterminate(x || z));
|
|
||||||
assert(y || z);
|
|
||||||
|
|
||||||
assert(indeterminate(y && indeterminate));
|
|
||||||
assert(indeterminate(indeterminate && y));
|
|
||||||
assert(!(x && indeterminate));
|
|
||||||
assert(!(indeterminate && x));
|
|
||||||
|
|
||||||
assert(indeterminate || y);
|
|
||||||
assert(y || indeterminate);
|
|
||||||
assert(indeterminate(x || indeterminate));
|
|
||||||
assert(indeterminate(indeterminate || x));
|
|
||||||
|
|
||||||
// Test the if (z) ... else (!z) ... else ... idiom
|
|
||||||
if (z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else if (!z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
z = true;
|
|
||||||
if (z) {
|
|
||||||
assert(true);
|
|
||||||
}
|
|
||||||
else if (!z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
z = false;
|
|
||||||
if (z) {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
else if (!z) {
|
|
||||||
assert(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "no errors detected\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -1,343 +0,0 @@
|
|||||||
/*=============================================================================
|
|
||||||
Copyright (c) 2001-2003 Joel de Guzman
|
|
||||||
|
|
||||||
Use, modification and distribution is subject to 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)
|
|
||||||
==============================================================================*/
|
|
||||||
#include <boost/test/minimal.hpp>
|
|
||||||
#include <boost/utility/type_deduction.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <complex>
|
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
#include <boost/static_assert.hpp>
|
|
||||||
|
|
||||||
namespace boost
|
|
||||||
{
|
|
||||||
BOOST_UNARY_RESULT_OF(-x, result_of_negate);
|
|
||||||
BOOST_UNARY_RESULT_OF(+x, result_of_posit);
|
|
||||||
BOOST_UNARY_RESULT_OF(!x, result_of_logical_not);
|
|
||||||
BOOST_UNARY_RESULT_OF(~x, result_of_invert);
|
|
||||||
BOOST_UNARY_RESULT_OF(&x, result_of_reference);
|
|
||||||
BOOST_UNARY_RESULT_OF(*x, result_of_dereference);
|
|
||||||
|
|
||||||
BOOST_UNARY_RESULT_OF(++x, result_of_pre_increment);
|
|
||||||
BOOST_UNARY_RESULT_OF(--x, result_of_pre_decrement);
|
|
||||||
BOOST_UNARY_RESULT_OF(x++, result_of_post_increment);
|
|
||||||
BOOST_UNARY_RESULT_OF(x--, result_of_post_decrement);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x = y, result_of_assign);
|
|
||||||
BOOST_ASYMMETRIC_BINARY_RESULT_OF(x[y], result_of_index);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x += y, result_of_plus_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x -= y, result_of_minus_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x *= y, result_of_multiplies_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x /= y, result_of_divides_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x %= y, result_of_modulus_assign);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x &= y, result_of_and_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x |= y, result_of_or_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x ^= y, result_of_xor_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x <<= y, result_of_shift_left_assign);
|
|
||||||
BOOST_BINARY_RESULT_OF(x >>= y, result_of_shift_right_assign);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x + y, result_of_plus);
|
|
||||||
BOOST_BINARY_RESULT_OF(x - y, result_of_minus);
|
|
||||||
BOOST_BINARY_RESULT_OF(x * y, result_of_multiplies);
|
|
||||||
BOOST_BINARY_RESULT_OF(x / y, result_of_divides);
|
|
||||||
BOOST_BINARY_RESULT_OF(x % y, result_of_modulus);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x & y, result_of_and);
|
|
||||||
BOOST_BINARY_RESULT_OF(x | y, result_of_or);
|
|
||||||
BOOST_BINARY_RESULT_OF(x ^ y, result_of_xor);
|
|
||||||
BOOST_BINARY_RESULT_OF(x << y, result_of_shift_left);
|
|
||||||
BOOST_BINARY_RESULT_OF(x >> y, result_of_shift_right);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x == y, result_of_equal_to);
|
|
||||||
BOOST_BINARY_RESULT_OF(x != y, result_of_not_equal_to);
|
|
||||||
BOOST_BINARY_RESULT_OF(x < y, result_of_less);
|
|
||||||
BOOST_BINARY_RESULT_OF(x <= y, result_of_less_equal);
|
|
||||||
BOOST_BINARY_RESULT_OF(x > y, result_of_greater);
|
|
||||||
BOOST_BINARY_RESULT_OF(x >= y, result_of_greater_equal);
|
|
||||||
|
|
||||||
BOOST_BINARY_RESULT_OF(x && y, result_of_logical_and);
|
|
||||||
BOOST_BINARY_RESULT_OF(x || y, result_of_logical_or);
|
|
||||||
BOOST_BINARY_RESULT_OF(true ? x : y, result_of_if_else);
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace boost;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
struct X {};
|
|
||||||
X operator+(X, int);
|
|
||||||
|
|
||||||
struct Y {};
|
|
||||||
Y* operator+(Y, int);
|
|
||||||
|
|
||||||
struct Z {};
|
|
||||||
Z const* operator+(Z const&, int);
|
|
||||||
Z& operator+(Z&, int);
|
|
||||||
bool operator==(Z, Z);
|
|
||||||
bool operator==(Z, int);
|
|
||||||
|
|
||||||
struct W {};
|
|
||||||
Z operator+(W, int);
|
|
||||||
bool operator==(W, Z);
|
|
||||||
|
|
||||||
int
|
|
||||||
test_main(int, char*[])
|
|
||||||
{
|
|
||||||
// PLUS
|
|
||||||
{
|
|
||||||
typedef result_of_plus<int, double>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, double>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<double, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, double>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<int, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<float, short>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, float>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<char, short>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<long, short>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, long>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<long, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, long>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<X, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<Y, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, Y*>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<Z, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, Z&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<Z const, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, Z const*>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<complex<double>, double>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, complex<double> >::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<double, complex<double> >::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, complex<double> >::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus<int*, size_t>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int*>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// INDEX
|
|
||||||
{
|
|
||||||
typedef result_of_index<int(&)[3], int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<X(&)[3], int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<X const(&)[3], int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X const&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<X*, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<X const*, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X const&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<int>, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, vector<int>::reference>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<int> const, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<X> const, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, vector<X>::const_reference>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<X>, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, vector<X>::reference>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<string, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, string::reference>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<int>::iterator, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, vector<int>::iterator::reference>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<int>::const_iterator, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<vector<X>::const_iterator, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, vector<X>::const_iterator::reference>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_index<map<char, X>, char>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, map<char, X>::mapped_type>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUS ASSIGN
|
|
||||||
{
|
|
||||||
typedef result_of_plus_assign<int, char>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus_assign<double, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, double&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_plus_assign<complex<double>, double>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, complex<double>&>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// SHIFT LEFT
|
|
||||||
{
|
|
||||||
typedef result_of_shift_left<int, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_shift_left<short, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_shift_left<ostream, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, ostream&>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// EQUAL
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<int, double>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<double, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<int, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<float, short>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<char, short>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<Z, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<Z, Z>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_equal_to<W, Z>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, bool>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// MINUS (pointers)
|
|
||||||
{
|
|
||||||
typedef result_of_minus<X*, X*>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, std::ptrdiff_t>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEREFERENCE
|
|
||||||
{
|
|
||||||
typedef result_of_dereference<X*>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_dereference<vector<X>::iterator>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_dereference<shared_ptr<X> >::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X&>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ADDRESS OF
|
|
||||||
{
|
|
||||||
typedef result_of_reference<X>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X*>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_reference<X const>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X const*>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRE INCREMENT
|
|
||||||
{
|
|
||||||
typedef result_of_pre_increment<int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int&>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST INCREMENT
|
|
||||||
{
|
|
||||||
typedef result_of_post_increment<int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// IF-ELSE-EXPRESSION ( c ? a : b )
|
|
||||||
{
|
|
||||||
typedef result_of_if_else<int, char>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_if_else<int, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_if_else<int const, int const>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, int>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_if_else<X, X>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X&>::value));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
typedef result_of_if_else<X const&, X const&>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, X const&>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEDUCTION FAILURE
|
|
||||||
{
|
|
||||||
typedef result_of_plus<W, int>::type result;
|
|
||||||
BOOST_STATIC_ASSERT((is_same<result, error_cant_deduce_type>::value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
Reference in New Issue
Block a user