diff --git a/doc/enable_if.html b/doc/enable_if.html new file mode 100644 index 0000000..1b927fb --- /dev/null +++ b/doc/enable_if.html @@ -0,0 +1,362 @@ + + +
+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; +} ++ + +
+ +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.
+ +template <bool B, class T = void> +struct enable_if { + typedef T type; +}; + +template <class T> +struct enable_if<false, T> {}; + ++An instantiation of the enable_if 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 +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. +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; } + ++The disable_if template is provided as well, and has the +same functionality as enable_if 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; } + ++ + +
+ +template <class T> +typename 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.
+ +template <class T, class Enable = void> +class A { ... }; + +template <class T> +class A<T, typename enable_if<is_integral<T>::value>::type> { ... }; + +template <class T> +class A<T, typename enable_if<is_float<T>::value>::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) +is the correct value.
+ +template <class T> +typename enable_if<boost::is_integral<T>::value, void>::type foo(T t) {} + +template <class T> +typename enable_if<boost::is_arithmetic<T>::value, 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.
+ +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 +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.
+ +template<class T, class U> +typename enable_if_lazy<is_multipliable<T, U>::value, mult_traits<T, U> >::type +operator*(const T& t, const U& u) { ... } + +The second argument of enable_if_lazy must be a class type +that defines a nested type named type whenever the first +parameter (the condition) is true.
+ +template <class T> struct dummy { dummy(int) {} }; + +template <class T> +typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t); + +template <class T> +typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t); + +Two workarounds can be applied: +
+ +template <class T> struct dummy { dummy(int) {} }; + +template <class T> +typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t, dummy<0> = 0); + +template <class T> +typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t, dummy<1> = 0); +
+ +namespace A { + template <class T> + typename enable_if<boost::is_arithmetic<T>::value, T>::type foo(T t); +} + +namespace B { + template <class T> + typename enable_if<!boost::is_arithmetic<T>::value, T>::type foo(T t); +} + +using A::foo; +using B::foo; ++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 help for templated operators that +need to be defined as member functions (assignment and +subscript operators). +
This document was translated from LATEX by +HEVEA. ++ +