mirror of
https://github.com/boostorg/utility.git
synced 2025-05-08 18:34:02 +00:00
465 lines
19 KiB
HTML
465 lines
19 KiB
HTML
<!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="Microsoft FrontPage 5.0">
|
|
</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="../../boost.png" align="center" width="277" height="86">enable_if</h1>
|
|
<BR>
|
|
<BR>
|
|
Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.<BR>
|
|
Copyright 2011 Matt Calabrese.<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 were 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="../type_traits/index.html">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>
|
|
With respect to function templates, <TT>enable_if</TT> can be used in multiple different ways:
|
|
|
|
<UL>
|
|
<LI>As the return type of an instantiatied function
|
|
<LI>As an extra parameter of an instantiated function
|
|
<LI>As an extra template parameter (useful only in a compiler that supports C++0x default
|
|
arguments for function template parameters, see <A href="#sec:enable_if_0x">Enabling function
|
|
templates in C++0x</a> for details)
|
|
</UL>
|
|
|
|
In the previous section, the return type form of <TT>enable_if</TT> was shown. As an example
|
|
of using the form of <TT>enable_if</TT> that works via an extra function parameter, 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>
|
|
Which way to write the enabler is largely a matter of taste, but for certain functions, only a
|
|
subset of the options is possible:
|
|
<UL><LI>
|
|
Many operators have a fixed number of arguments, thus <TT>enable_if</TT> must be used either in the
|
|
return type or in an extra template parameter.
|
|
<LI>Functions that have a variadic parameter list must use either the return type form or an extra
|
|
template parameter.
|
|
<LI>Constructors do not have a return type so you must use either an extra function parameter or an
|
|
extra template parameter.
|
|
<LI>Constructors that have a variadic parameter list must an extra template parameter.
|
|
<LI>Conversion operators can only be written with an extra template parameter.
|
|
</UL>
|
|
<!--TOC subsection Enabling function templates in C++0x-->
|
|
|
|
<A NAME="sec:enable_if_0x"></A>
|
|
<H3><A NAME="htoc7">3.1</A> Enabling function templates in C++0x</H3><!--SEC END -->
|
|
|
|
In a compiler which supports C++0x default arguments for function template parameters, you can
|
|
enable and disable function templates by adding an additional template parameter. This approach
|
|
works in all situations where you would use either the return type form of <TT>enable_if</TT> or
|
|
the function parameter form, including operators, constructors, variadic function templates, and
|
|
even overloaded conversion operations.
|
|
|
|
As an example:
|
|
|
|
<PRE>#include <boost/type_traits/is_arithmetic.hpp>
|
|
#include <boost/type_traits/is_pointer.hpp>
|
|
#include <boost/utility/enable_if.hpp>
|
|
|
|
class test
|
|
{
|
|
public:
|
|
// A constructor that works for any argument list of size 10
|
|
template< class... T
|
|
, typename boost::enable_if_c< sizeof...( T ) == 10, int >::type = 0
|
|
>
|
|
test( T&&... );
|
|
|
|
// A conversion operation that can convert to any arithmetic type
|
|
template< class T
|
|
, typename boost::enable_if< boost::is_arithmetic< T >, int >::type = 0
|
|
>
|
|
operator T() const;
|
|
|
|
// A conversion operation that can convert to any pointer type
|
|
template< class T
|
|
, typename boost::enable_if< boost::is_pointer< T >, int >::type = 0
|
|
>
|
|
operator T() const;
|
|
};
|
|
|
|
int main()
|
|
{
|
|
// Works
|
|
test test_( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 );
|
|
|
|
// Fails as expected
|
|
test fail_construction( 1, 2, 3, 4, 5 );
|
|
|
|
// Works by calling the conversion operator enabled for arithmetic types
|
|
int arithmetic_object = test_;
|
|
|
|
// Works by calling the conversion operator enabled for pointer types
|
|
int* pointer_object = test_;
|
|
|
|
// Fails as expected
|
|
struct {} fail_conversion = test_;
|
|
}
|
|
|
|
</PRE>
|
|
|
|
<!--TOC subsection Enabling template class specializations-->
|
|
|
|
<H3><A NAME="htoc7">3.2</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="htoc8">3.3</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="htoc9">3.4</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="htoc10">3.5</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 <int> 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/>
|
|
<p>Copyright Jaakko Järvi<sup>*</sup>, Jeremiah Willcock<sup>*</sup>, Andrew Lumsdaine<sup>*</sup>, Matt Calabrese<BR>
|
|
<EM>{jajarvi|jewillco|lums}@osl.iu.edu, rivorus@gmail.com</EM><BR>
|
|
<sup>*</sup>Indiana University<BR>
|
|
Open Systems Lab<br/>
|
|
Use, modification and distribution are subject to the
|
|
Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt
|
|
or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
|
http://www.boost.org/LICENSE_1_0.txt
|
|
</a>).
|
|
</p>
|
|
<!--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>
|