diff --git a/enable_if.html b/enable_if.html new file mode 100644 index 0000000..349189e --- /dev/null +++ b/enable_if.html @@ -0,0 +1,417 @@ + + +enable_if + + + + + + + + + + +
+
+ + +

+enable_if

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

1  Introduction

+ + +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 templates can also be +applied to enable class template specializations. Applications of +enable_if are discussed in length +in [1] and [2].
+
+ + +

1.1  Synopsis

+ + +
+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;
+}
+
+ + +

1.2  Background

+ + +Sensible operation of template function overloading in C++ relies +on the SFINAE (substitution-failure-is-not-an-error) +principle [3]: 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 [1], +demonstrates why this is important: +
+
+int negate(int i) { return -i; }
+
+template <class F>
+typename F::result_type negate(const F& f) { return -f(); }
+
+
+Suppose the compiler encounters the call negate(1). 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 +F as int would result in: +
+
+int::result_type negate(const int&);
+
+
+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 negate is simply removed from the overload resolution set.
+
+The enable_if templates are tools for controlled creation of the SFINAE +conditions.
+
+ + +

2  The enable_if templates

+ + +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_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> {};
+
+
+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_c<B, T>::type is either a valid or an invalid type +expression, depending on the value of B. +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_c<boost::is_arithmetic<T>::value, T>::type 
+foo(T t) { return t; }
+
+
+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_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; }
+
+
+ + +

3  Using enable_if

+ + +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 in the previous section could also be written +as: +
+
+template <class T>
+T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0); 
+
+
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 +alternative is possible: + + + +

3.1  Enabling template class specializations

+ + +Class template specializations can be enabled or disabled with enable_if. +One extra template parameter needs to be added for the enabler expressions. +This parameter has the default value void. +For example: +
+
+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> { ... };
+
+
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 again, the second argument to enable_if is not needed; the default (void) +is the correct value.
+
+ + +

3.2  Overlapping enabler conditions

+ + +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: +
+
+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) {}
+
+
+All integral types are also arithmetic. Therefore, say, for the call foo(1), +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.
+
+The above discussion applies to using enable_if in class template +partial specializations as well.
+
+ + +

3.3  Lazy enable_if

+ + +In some cases it is necessary to avoid instantiating part of a +function signature unless an enabling condition is true. For example: +
+
+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) { ... }
+
+
Assume the class template mult_traits is a traits class defining +the resulting type of a multiplication operator. The is_multipliable traits +class specifies for which types to enable the operator. Whenever +is_multipliable<A, B>::value is true for some types A and B, +then mult_traits<A, B>::type is defined.
+
+Now, trying to invoke (some other overload) of operator* with, say, operand types C and D +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 lazy_enable_if +and lazy_disable_if templates (and their _c versions) can be used in such +situations: +
+
+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) { ... }
+
+
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.
+
+ + +
Note
+ +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, is_multipliable<T, U>::value defines when +mult_traits<T, U>::type is valid.
+
+ + +

3.4  Compiler workarounds

+ + +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: +
+
+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);
+
+
Two workarounds can be applied: + + + +

4  Acknowledgements

+ +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. +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. +Concept-controlled polymorphism. +In Frank Pfennig and Yannis Smaragdakis, editors, Generative + Programming and Component Engineering, volume 2830 of LNCS, pages + 228--244. Springer Verlag, September 2003.
+
+
[3]
+David Vandevoorde and Nicolai M. Josuttis. +C++ Templates: The Complete Guide. +Addison-Wesley, 2002.
+ + + + + +
+ +Contributed by:
+Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine
+{jajarvi|jewillco|lums}@osl.iu.edu
+Indiana University
+Open Systems Lab + + + +
+
This document was translated from LATEX by +HEVEA. +
+ + diff --git a/include/boost/utility/enable_if.hpp b/include/boost/utility/enable_if.hpp new file mode 100644 index 0000000..c1f217d --- /dev/null +++ b/include/boost/utility/enable_if.hpp @@ -0,0 +1,69 @@ +// Boost enable_if library + +// Copyright 2003 © The Trustees of Indiana University. + +// 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) + +// 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 + struct enable_if_c { + typedef T type; + }; + + template + struct enable_if_c {}; + + template + struct enable_if : public enable_if_c {}; + + template + struct lazy_enable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_enable_if_c {}; + + template + struct lazy_enable_if : public lazy_enable_if_c {}; + + + template + struct disable_if_c { + typedef T type; + }; + + template + struct disable_if_c {}; + + template + struct disable_if : public disable_if_c {}; + + template + struct lazy_disable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_disable_if_c {}; + + template + struct lazy_disable_if : public lazy_disable_if_c {}; + + + +} // namespace boost + +#endif