| [/ |
| / Copyright (c) 2003, 2004 Jaakko Jarvi |
| / Copyright (c) 2008 John Maddock |
| / Copyright (c) 2011, 2013 Jeremiah Willcock |
| / Copyright (c) 2014 Glen Fernandes |
| / |
| / 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) |
| /] |
| |
| [section:enable_if enable_if] |
| |
| [simplesect Authors] |
| |
| * Jaakko J\u00E4rvi |
| * Jeremiah Willcock |
| * Andrew Lumsdaine |
| |
| [endsimplesect] |
| |
| [section 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 |
| [link REF1 \[1\]] and [link REF2 \[2\]]. |
| |
| [section Header <boost/core/enable_if.hpp>] |
| |
| `` |
| 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; |
| } |
| `` |
| |
| [endsect] |
| |
| [section Background] |
| |
| Sensible operation of template function overloading in C++ |
| relies on the /SFINAE/ (substitution-failure-is-not-an-error) |
| principle [link REF3 \[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 [link REF1 \[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 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 `negate` is simply removed from the overload resolution set. |
| |
| The `enable_if` templates are tools for controlled creation of |
| the SFINAE conditions. |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section 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 the section [link |
| core.enable_if.using_enable_if.enable_if_lazy below]. 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; } |
| `` |
| |
| [endsect] |
| |
| [section:using_enable_if Using enable_if] |
| |
| The `enable_if` templates are defined in |
| `boost/utility/enable_if.hpp`, which is included by |
| `boost/utility.hpp`. |
| |
| With respect to function templates, `enable_if` can be used in |
| multiple different ways: |
| |
| * As the return type of an instantiatied function |
| * As an extra parameter of an instantiated function |
| * As an extra template parameter (useful only in a compiler |
| that supports C++0x default arguments for function template |
| parameters, see [link |
| core.enable_if.using_enable_if.enable_if_0x Enabling function |
| templates in C++0x] for details. |
| |
| In the previous section, the return type form of `enable_if` |
| was shown. As an example of using the form of `enable_if` that |
| works via an extra function parameter, 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. |
| |
| Which way to write the enabler is largely a matter of taste, |
| but for certain functions, only a subset of the options is |
| possible: |
| |
| * Many operators have a fixed number of arguments, thus |
| `enable_if` must be used either in the return type or in an |
| extra template parameter. |
| * Functions that have a variadic parameter list must use either |
| the return type form or an extra template parameter. |
| * Constructors do not have a return type so you must use either |
| an extra function parameter or an extra template parameter. |
| * Constructors that have a variadic parameter list must an |
| extra template parameter. |
| * Conversion operators can only be written with an extra |
| template parameter. |
| |
| [section:enable_if_0x Enabling function templates in C++0x] |
| |
| 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 `enable_if` or the function |
| parameter form, including operators, constructors, variadic |
| function templates, and even overloaded conversion operations. |
| |
| As an example: |
| |
| `` |
| #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_; |
| } |
| `` |
| |
| [endsect] |
| |
| [section 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. |
| |
| The `enable_if_has_type` template is usable this scenario but instead of |
| using a type traits to enable or disable a specialization, it use a |
| SFINAE context to check for the existence of a dependent type inside |
| its parameter. For example, the following structure extracts a dependent |
| `value_type` from T if and only if `T::value_type` exists. |
| |
| `` |
| template <class T, class Enable = void> |
| class value_type_from |
| { |
| typedef T type; |
| }; |
| |
| template <class T> |
| class value_type_from<T, typename enable_if_has_type<typename T::value_type>::type> |
| { |
| typedef typename T::value_type type; |
| }; |
| `` |
| |
| [endsect] |
| |
| [section 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. |
| |
| [endsect] |
| |
| [section:enable_if_lazy 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.] |
| |
| [endsect] |
| |
| [section 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: |
| |
| * Use an extra dummy parameter which disambiguates the |
| functions. Use a default value for it to hide the parameter |
| from the caller. For example: |
| `` |
| 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); |
| `` |
| * Define the functions in different namespaces and bring them |
| into a common namespace with `using` declarations: |
| `` |
| 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; |
| `` |
| 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). |
| |
| [endsect] |
| |
| [endsect] |
| |
| [section Acknowledgements] |
| |
| We are grateful to Howard Hinnant, Jason Shirk, Paul |
| Mensonides, and Richard Smith whose findings have |
| influenced the library. |
| |
| [endsect] |
| |
| [section References] |
| |
| * [#REF1] \[1\] Jaakko J\u00E4rvi, Jeremiah Willcock, Howard |
| Hinnant, and Andrew Lumsdaine. Function overloading based on |
| arbitrary properties of types. /C++ Users Journal/, |
| 21(6):25--32, June 2003. |
| * [#REF2] \[2\] Jaakko J\u00E4rvi, 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. |
| * [#REF3] \[3\] David Vandevoorde and Nicolai M. Josuttis. |
| /C++ Templates: The Complete Guide/. Addison-Wesley, 2002. |
| |
| [endsect] |
| |
| [endsect] |