diff --git a/doc/enable_if.html b/doc/enable_if.html index 1b927fb..cda96a9 100644 --- a/doc/enable_if.html +++ b/doc/enable_if.html @@ -7,7 +7,7 @@ - + @@ -20,18 +20,19 @@ enable_if

-Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.
+Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.

1  Introduction

-The enable_if template is a tool for selectively including -functions into the overload resolution set based on the properties of -the template arguments. For example, one can define function templates that +The enable_if 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 enable_if template can also be +defined by a traits class. The enable_if templates can also be applied to enable class template specializations. Applications of enable_if are discussed in length in [1] and [2].
@@ -43,10 +44,15 @@ in [1] and&n
 namespace boost {
-  template <bool B, class T = void> struct enable_if;
-  template <bool B, class T = void> struct disable_if;
-  template <bool B, class T> struct enable_if_lazy;
-  template <bool B, class T> struct disable_if_lazy;
+  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;
 }
 
@@ -85,50 +91,80 @@ where the return type is invalid. If this was an error, adding an unrelated func Due to the SFINAE principle the above example is not, however, erroneous. The latter definition of negate is simply removed from the overload resolution set.

-The enable_if template is a tool for controlled creation of the SFINAE +The enable_if templates are tools for controlled creation of the SFINAE conditions.

- + -

2  The enable_if template

+

2  The enable_if templates

-The definition of enable_if is as follows: +The names of the enable_if templates have three parts: an optional lazy_ tag, +either enable_if or disable_if, and an optional _c tag. +All eight combinations of these parts are supported. +The meaning of the lazy_ tag is described in Section 3.3. +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 bool value +(_c suffix), or a type containing a static bool constant named value (no suffix). +The latter version interoperates with Boost.MPL.
+
+The definitions of enable_if_c and enable_if are as follows (we use enable_if templates +unqualified but they are in the boost namespace).
 
 template <bool B, class T = void>
-struct enable_if {
+struct enable_if_c {
   typedef T type;
 };
 
 template <class T>
-struct enable_if<false, T> {};
+struct enable_if_c<false, T> {};
+
+template <class Cond, class T = void>
+struct enable_if : public enable_if_c<Cond::value, T> {};
 
 
-An instantiation of the enable_if template with the parameter +An instantiation of the enable_if_c template with the parameter B as true contains a member type type, defined to be T. If B is -false, no such member is defined. Thus -enable_if<B, T>::type is either a valid or an invalid type +false, no such member is defined. Thus +enable_if_c<B, T>::type is either a valid or an invalid type expression, depending on the value of B. -When valid, enable_if<B, T>::type equals T. -The enable_if can thus be used for controlling when functions are considered for -overload resolution and when not. +When valid, enable_if_c<B, T>::type equals T. +The enable_if_c 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 Boost type_traits library):
 
 template <class T>
-typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t) { return t; }
+typename enable_if_c<boost::is_arithmetic<T>::value, T>::type 
+foo(T t) { return t; }
 
 
-The disable_if template is provided as well, and has the -same functionality as enable_if except for the negated condition. The following +The disable_if_c template is provided as well, and has the +same functionality as enable_if_c except for the negated condition. The following function is enabled for all non-arithmetic types.
 
 template <class T>
-typename disable_if<boost::is_arithmetic<T>::value, T>::type foo(T t) { return t; }
+typename disable_if_c<boost::is_arithmetic<T>::value, T>::type 
+bar(T t) { return t; }
+
+
+For easier syntax in some cases and interoperation with Boost.MPL we provide versions of +the enable_if templates taking any type with a bool member constant named +value as the condition argument. +The MPL bool_, and_, or_, and not_ 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 foo can be alternatively written as: +
+
+template <class T>
+typename enable_if<boost::is_arithmetic<T>, T>::type 
+foo(T t) { return t; }
 
 
@@ -140,17 +176,17 @@ The enable_if templates are defined in boost/utility/enable_if.hpp, which is included by boost/utility.hpp.

The enable_if template can be used either as the return type, or as an -extra argument. For example, the foo function below could also be written +extra argument. For example, the foo function in the previous section could also be written as:
 
 template <class T>
-typename T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0); 
+T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0); 
 
-
Hence, an extra argument of type void* is added, but it is given -a default value to keep the argument hidden from the client code. -Note that the type parameter was not given to enable_if, the default -void gives the desired type.
+Hence, an extra parameter of type void* 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 enable_if, as the default +void gives the desired behavior.

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 @@ -176,17 +212,17 @@ template <class T, class Enable = void> class A { ... }; template <class T> -class A<T, typename enable_if<is_integral<T>::value>::type> { ... }; +class A<T, typename enable_if<is_integral<T> >::type> { ... }; template <class T> -class A<T, typename enable_if<is_float<T>::value>::type> { ... }; +class A<T, typename enable_if<is_float<T> >::type> { ... }; Instantiating A 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 no type parameter is given to enable_if; the default (void) +Note that again, the second argument to enable_if is not needed; the default (void) is the correct value.

@@ -203,10 +239,12 @@ lead to ambiguities. For example:
 
 template <class T>
-typename enable_if<boost::is_integral<T>::value, void>::type foo(T t) {}
+typename enable_if<boost::is_integral<T>, void>::type 
+foo(T t) {}
 
 template <class T>
-typename enable_if<boost::is_arithmetic<T>::value, void>::type foo(T t) {}
+typename enable_if<boost::is_arithmetic<T>, void>::type 
+foo(T t) {}
 
 
All integral types are also arithmetic. Therefore, say, for the call foo(1), @@ -230,7 +268,7 @@ and there is variation among compilers. For example: template <class T, class U> class mult_traits; template <class T, class U> -typename enable_if<is_multipliable<T, U>::value, typename mult_traits<T, U>::type>::type +typename enable_if<is_multipliable<T, U>, typename mult_traits<T, U>::type>::type operator*(const T& t, const U& u) { ... } Assume the class template mult_traits is a traits class defining @@ -243,16 +281,16 @@ Now, trying to invoke (some other overload) of operator* with, say, ope for which is_multipliable<C, D>::value is false and mult_traits<C, D>::type 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 enable_if_lazy -and disable_if_lazy templates can be used in such +the invalid type occurs as an argument to another template. The lazy_enable_if +and lazy_disable_if templates (and their _c versions) can be used in such situations:
 
 template<class T, class U>
-typename enable_if_lazy<is_multipliable<T, U>::value, mult_traits<T, U> >::type
+typename lazy_enable_if<is_multipliable<T, U>, mult_traits<T, U> >::type
 operator*(const T& t, const U& u) { ... }
 
-
The second argument of enable_if_lazy must be a class type +The second argument of lazy_enable_if must be a class type that defines a nested type named type whenever the first parameter (the condition) is true.

@@ -269,10 +307,12 @@ some compilers (e.g. GCC 3.2) diagnose the following two functions as ambiguous: template <class T> struct dummy { dummy(int) {} }; template <class T> -typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t); +typename enable_if<boost::is_arithmetic<T>, T>::type +foo(T t); template <class T> -typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t); +typename disable_if<boost::is_arithmetic<T>, T>::type +foo(T t); Two workarounds can be applied: @@ -317,19 +362,19 @@ subscript operators).

4  Acknowledgements

-We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides and Richard +We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides, and Richard Smith whose findings have influenced the library.

References

[1]
-Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine. +Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine. Function overloading based on arbitrary properties of types. C/C++ Users Journal, 21(6):25--32, June 2003.

[2]
-Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine. +Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine. Concept-controlled polymorphism. In Proceedings of Generative Programming and Component Engineering (GPCE'03), September 2003. @@ -347,7 +392,7 @@ Addison-Wesley, 2002.

Contributed by:
-Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine
+Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine
{jajarvi|jewillco|lums}@osl.iu.edu
Indiana University
Open Systems Lab