Brian Silverman | 407d3cd | 2018-08-04 17:48:52 -0700 | [diff] [blame^] | 1 | [/ |
| 2 | / Copyright (c) 2003, 2004 Jaakko Jarvi |
| 3 | / Copyright (c) 2008 John Maddock |
| 4 | / Copyright (c) 2011, 2013 Jeremiah Willcock |
| 5 | / Copyright (c) 2014 Glen Fernandes |
| 6 | / |
| 7 | / Use, modification, and distribution is subject to the Boost Software |
| 8 | / License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| 9 | / http://www.boost.org/LICENSE_1_0.txt) |
| 10 | /] |
| 11 | |
| 12 | [section:enable_if enable_if] |
| 13 | |
| 14 | [simplesect Authors] |
| 15 | |
| 16 | * Jaakko J\u00E4rvi |
| 17 | * Jeremiah Willcock |
| 18 | * Andrew Lumsdaine |
| 19 | |
| 20 | [endsimplesect] |
| 21 | |
| 22 | [section Introduction] |
| 23 | |
| 24 | The `enable_if` family of templates is a set of tools to allow |
| 25 | a function template or a class template specialization to |
| 26 | include or exclude itself from a set of matching functions or |
| 27 | specializations based on properties of its template arguments. |
| 28 | For example, one can define function templates that are only |
| 29 | enabled for, and thus only match, an arbitrary set of types |
| 30 | defined by a traits class. The `enable_if` templates can also |
| 31 | be applied to enable class template specializations. |
| 32 | Applications of `enable_if` are discussed in length in |
| 33 | [link REF1 \[1\]] and [link REF2 \[2\]]. |
| 34 | |
| 35 | [section Header <boost/core/enable_if.hpp>] |
| 36 | |
| 37 | `` |
| 38 | namespace boost { |
| 39 | template <class Cond, class T = void> struct enable_if; |
| 40 | template <class Cond, class T = void> struct disable_if; |
| 41 | template <class Cond, class T> struct lazy_enable_if; |
| 42 | template <class Cond, class T> struct lazy_disable_if; |
| 43 | |
| 44 | template <bool B, class T = void> struct enable_if_c; |
| 45 | template <bool B, class T = void> struct disable_if_c; |
| 46 | template <bool B, class T> struct lazy_enable_if_c; |
| 47 | template <bool B, class T> struct lazy_disable_if_c; |
| 48 | } |
| 49 | `` |
| 50 | |
| 51 | [endsect] |
| 52 | |
| 53 | [section Background] |
| 54 | |
| 55 | Sensible operation of template function overloading in C++ |
| 56 | relies on the /SFINAE/ (substitution-failure-is-not-an-error) |
| 57 | principle [link REF3 \[3\]]: if an invalid argument or return |
| 58 | type is formed during the instantiation of a function template, |
| 59 | the instantiation is removed from the overload resolution set |
| 60 | instead of causing a compilation error. The following example, |
| 61 | taken from [link REF1 \[1\]], demonstrates why this is |
| 62 | important: |
| 63 | |
| 64 | `` |
| 65 | int negate(int i) { return -i; } |
| 66 | |
| 67 | template <class F> |
| 68 | typename F::result_type negate(const F& f) { return -f(); } |
| 69 | `` |
| 70 | |
| 71 | Suppose the compiler encounters the call `negate(1)`. The first |
| 72 | definition is obviously a better match, but the compiler must |
| 73 | nevertheless consider (and instantiate the prototypes) of both |
| 74 | definitions to find this out. Instantiating the latter |
| 75 | definition with `F` as `int` would result in: |
| 76 | |
| 77 | `` |
| 78 | int::result_type negate(const int&); |
| 79 | `` |
| 80 | |
| 81 | where the return type is invalid. If this were an error, adding |
| 82 | an unrelated function template (that was never called) could |
| 83 | break otherwise valid code. Due to the SFINAE principle the |
| 84 | above example is not, however, erroneous. The latter definition |
| 85 | of `negate` is simply removed from the overload resolution set. |
| 86 | |
| 87 | The `enable_if` templates are tools for controlled creation of |
| 88 | the SFINAE conditions. |
| 89 | |
| 90 | [endsect] |
| 91 | |
| 92 | [endsect] |
| 93 | |
| 94 | [section The enable_if templates] |
| 95 | |
| 96 | The names of the `enable_if` templates have three parts: an |
| 97 | optional `lazy_` tag, either `enable_if` or `disable_if`, and |
| 98 | an optional `_c` tag. All eight combinations of these parts |
| 99 | are supported. The meaning of the `lazy_` tag is described |
| 100 | in the section [link |
| 101 | core.enable_if.using_enable_if.enable_if_lazy below]. The |
| 102 | second part of the name indicates whether a true condition |
| 103 | argument should enable or disable the current overload. The |
| 104 | third part of the name indicates whether the condition |
| 105 | argument is a `bool` value (`_c` suffix), or a type containing |
| 106 | a static `bool` constant named `value` (no suffix). The latter |
| 107 | version interoperates with Boost.MPL. |
| 108 | |
| 109 | The definitions of `enable_if_c` and `enable_if` are as follows |
| 110 | (we use `enable_if` templates unqualified but they are in the |
| 111 | `boost` namespace). |
| 112 | |
| 113 | `` |
| 114 | template <bool B, class T = void> |
| 115 | struct enable_if_c { |
| 116 | typedef T type; |
| 117 | }; |
| 118 | |
| 119 | template <class T> |
| 120 | struct enable_if_c<false, T> {}; |
| 121 | |
| 122 | template <class Cond, class T = void> |
| 123 | struct enable_if : public enable_if_c<Cond::value, T> {}; |
| 124 | `` |
| 125 | |
| 126 | An instantiation of the `enable_if_c` template with the |
| 127 | parameter `B` as `true` contains a member type `type`, defined |
| 128 | to be `T`. If `B` is `false`, no such member is defined. Thus |
| 129 | `enable_if_c<B, T>::type` is either a valid or an invalid type |
| 130 | expression, depending on the value of `B`. When valid, |
| 131 | `enable_if_c<B, T>::type` equals `T`. The `enable_if_c` |
| 132 | template can thus be used for controlling when functions are |
| 133 | considered for overload resolution and when they are not. For |
| 134 | example, the following function is defined for all arithmetic |
| 135 | types (according to the classification of the Boost |
| 136 | *type_traits* library): |
| 137 | |
| 138 | `` |
| 139 | template <class T> |
| 140 | typename enable_if_c<boost::is_arithmetic<T>::value, T>::type |
| 141 | foo(T t) { return t; } |
| 142 | `` |
| 143 | |
| 144 | The `disable_if_c` template is provided as well, and has the |
| 145 | same functionality as `enable_if_c` except for the negated |
| 146 | condition. The following function is enabled for all |
| 147 | non-arithmetic types. |
| 148 | |
| 149 | `` |
| 150 | template <class T> |
| 151 | typename disable_if_c<boost::is_arithmetic<T>::value, T>::type |
| 152 | bar(T t) { return t; } |
| 153 | `` |
| 154 | |
| 155 | For easier syntax in some cases and interoperation with |
| 156 | Boost.MPL we provide versions of the `enable_if` templates |
| 157 | taking any type with a `bool` member constant named `value` as |
| 158 | the condition argument. The MPL `bool_`, `and_`, `or_`, and |
| 159 | `not_` templates are likely to be useful for creating such |
| 160 | types. Also, the traits classes in the Boost.Type_traits |
| 161 | library follow this convention. For example, the above example |
| 162 | function `foo` can be alternatively written as: |
| 163 | |
| 164 | `` |
| 165 | template <class T> |
| 166 | typename enable_if<boost::is_arithmetic<T>, T>::type |
| 167 | foo(T t) { return t; } |
| 168 | `` |
| 169 | |
| 170 | [endsect] |
| 171 | |
| 172 | [section:using_enable_if Using enable_if] |
| 173 | |
| 174 | The `enable_if` templates are defined in |
| 175 | `boost/utility/enable_if.hpp`, which is included by |
| 176 | `boost/utility.hpp`. |
| 177 | |
| 178 | With respect to function templates, `enable_if` can be used in |
| 179 | multiple different ways: |
| 180 | |
| 181 | * As the return type of an instantiatied function |
| 182 | * As an extra parameter of an instantiated function |
| 183 | * As an extra template parameter (useful only in a compiler |
| 184 | that supports C++0x default arguments for function template |
| 185 | parameters, see [link |
| 186 | core.enable_if.using_enable_if.enable_if_0x Enabling function |
| 187 | templates in C++0x] for details. |
| 188 | |
| 189 | In the previous section, the return type form of `enable_if` |
| 190 | was shown. As an example of using the form of `enable_if` that |
| 191 | works via an extra function parameter, the `foo` function in |
| 192 | the previous section could also be written as: |
| 193 | |
| 194 | `` |
| 195 | template <class T> |
| 196 | T foo(T t, |
| 197 | typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0); |
| 198 | `` |
| 199 | |
| 200 | Hence, an extra parameter of type `void*` is added, but it is |
| 201 | given a default value to keep the parameter hidden from client |
| 202 | code. Note that the second template argument was not given to |
| 203 | `enable_if`, as the default `void` gives the desired behavior. |
| 204 | |
| 205 | Which way to write the enabler is largely a matter of taste, |
| 206 | but for certain functions, only a subset of the options is |
| 207 | possible: |
| 208 | |
| 209 | * Many operators have a fixed number of arguments, thus |
| 210 | `enable_if` must be used either in the return type or in an |
| 211 | extra template parameter. |
| 212 | * Functions that have a variadic parameter list must use either |
| 213 | the return type form or an extra template parameter. |
| 214 | * Constructors do not have a return type so you must use either |
| 215 | an extra function parameter or an extra template parameter. |
| 216 | * Constructors that have a variadic parameter list must an |
| 217 | extra template parameter. |
| 218 | * Conversion operators can only be written with an extra |
| 219 | template parameter. |
| 220 | |
| 221 | [section:enable_if_0x Enabling function templates in C++0x] |
| 222 | |
| 223 | In a compiler which supports C++0x default arguments for |
| 224 | function template parameters, you can enable and disable |
| 225 | function templates by adding an additional template parameter. |
| 226 | This approach works in all situations where you would use |
| 227 | either the return type form of `enable_if` or the function |
| 228 | parameter form, including operators, constructors, variadic |
| 229 | function templates, and even overloaded conversion operations. |
| 230 | |
| 231 | As an example: |
| 232 | |
| 233 | `` |
| 234 | #include <boost/type_traits/is_arithmetic.hpp> |
| 235 | #include <boost/type_traits/is_pointer.hpp> |
| 236 | #include <boost/utility/enable_if.hpp> |
| 237 | |
| 238 | class test |
| 239 | { |
| 240 | public: |
| 241 | // A constructor that works for any argument list of size 10 |
| 242 | template< class... T, |
| 243 | typename boost::enable_if_c< sizeof...( T ) == 10, |
| 244 | int >::type = 0> |
| 245 | test( T&&... ); |
| 246 | |
| 247 | // A conversion operation that can convert to any arithmetic type |
| 248 | template< class T, |
| 249 | typename boost::enable_if< boost::is_arithmetic< T >, |
| 250 | int >::type = 0> |
| 251 | operator T() const; |
| 252 | |
| 253 | // A conversion operation that can convert to any pointer type |
| 254 | template< class T, |
| 255 | typename boost::enable_if< boost::is_pointer< T >, |
| 256 | int >::type = 0> |
| 257 | operator T() const; |
| 258 | }; |
| 259 | |
| 260 | int main() |
| 261 | { |
| 262 | // Works |
| 263 | test test_( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ); |
| 264 | |
| 265 | // Fails as expected |
| 266 | test fail_construction( 1, 2, 3, 4, 5 ); |
| 267 | |
| 268 | // Works by calling the conversion operator enabled for arithmetic types |
| 269 | int arithmetic_object = test_; |
| 270 | |
| 271 | // Works by calling the conversion operator enabled for pointer types |
| 272 | int* pointer_object = test_; |
| 273 | |
| 274 | // Fails as expected |
| 275 | struct {} fail_conversion = test_; |
| 276 | } |
| 277 | `` |
| 278 | |
| 279 | [endsect] |
| 280 | |
| 281 | [section Enabling template class specializations] |
| 282 | |
| 283 | Class template specializations can be enabled or disabled with |
| 284 | `enable_if`. One extra template parameter needs to be added for |
| 285 | the enabler expressions. This parameter has the default value |
| 286 | `void`. For example: |
| 287 | |
| 288 | `` |
| 289 | template <class T, class Enable = void> |
| 290 | class A { ... }; |
| 291 | |
| 292 | template <class T> |
| 293 | class A<T, typename enable_if<is_integral<T> >::type> { ... }; |
| 294 | |
| 295 | template <class T> |
| 296 | class A<T, typename enable_if<is_float<T> >::type> { ... }; |
| 297 | `` |
| 298 | |
| 299 | Instantiating `A` with any integral type matches the first |
| 300 | specialization, whereas any floating point type matches the |
| 301 | second one. All other types match the primary template. |
| 302 | The condition can be any compile-time boolean expression that |
| 303 | depends on the template arguments of the class. Note that |
| 304 | again, the second argument to `enable_if` is not needed; the |
| 305 | default (`void`) is the correct value. |
| 306 | |
| 307 | The `enable_if_has_type` template is usable this scenario but instead of |
| 308 | using a type traits to enable or disable a specialization, it use a |
| 309 | SFINAE context to check for the existence of a dependent type inside |
| 310 | its parameter. For example, the following structure extracts a dependent |
| 311 | `value_type` from T if and only if `T::value_type` exists. |
| 312 | |
| 313 | `` |
| 314 | template <class T, class Enable = void> |
| 315 | class value_type_from |
| 316 | { |
| 317 | typedef T type; |
| 318 | }; |
| 319 | |
| 320 | template <class T> |
| 321 | class value_type_from<T, typename enable_if_has_type<typename T::value_type>::type> |
| 322 | { |
| 323 | typedef typename T::value_type type; |
| 324 | }; |
| 325 | `` |
| 326 | |
| 327 | [endsect] |
| 328 | |
| 329 | [section Overlapping enabler conditions] |
| 330 | |
| 331 | Once the compiler has examined the enabling conditions and |
| 332 | included the function into the overload resolution set, normal |
| 333 | C++ overload resolution rules are used to select the best |
| 334 | matching function. In particular, there is no ordering between |
| 335 | enabling conditions. Function templates with enabling |
| 336 | conditions that are not mutually exclusive can lead to |
| 337 | ambiguities. For example: |
| 338 | |
| 339 | `` |
| 340 | template <class T> |
| 341 | typename enable_if<boost::is_integral<T>, void>::type |
| 342 | foo(T t) {} |
| 343 | |
| 344 | template <class T> |
| 345 | typename enable_if<boost::is_arithmetic<T>, void>::type |
| 346 | foo(T t) {} |
| 347 | `` |
| 348 | |
| 349 | All integral types are also arithmetic. Therefore, say, for the |
| 350 | call `foo(1)`, both conditions are true and both functions are |
| 351 | thus in the overload resolution set. They are both equally good |
| 352 | matches and thus ambiguous. Of course, more than one enabling |
| 353 | condition can be simultaneously true as long as other arguments |
| 354 | disambiguate the functions. |
| 355 | |
| 356 | The above discussion applies to using `enable_if` in class |
| 357 | template partial specializations as well. |
| 358 | |
| 359 | [endsect] |
| 360 | |
| 361 | [section:enable_if_lazy Lazy enable_if] |
| 362 | |
| 363 | In some cases it is necessary to avoid instantiating part of a |
| 364 | function signature unless an enabling condition is true. For |
| 365 | example: |
| 366 | |
| 367 | `` |
| 368 | template <class T, class U> class mult_traits; |
| 369 | |
| 370 | template <class T, class U> |
| 371 | typename enable_if<is_multipliable<T, U>, |
| 372 | typename mult_traits<T, U>::type>::type |
| 373 | operator*(const T& t, const U& u) { ... } |
| 374 | `` |
| 375 | |
| 376 | Assume the class template `mult_traits` is a traits class |
| 377 | defining the resulting type of a multiplication operator. The |
| 378 | `is_multipliable` traits class specifies for which types to |
| 379 | enable the operator. Whenever `is_multipliable<A, B>::value` is |
| 380 | `true` for some types `A` and `B`, then |
| 381 | `mult_traits<A, B>::type` is defined. |
| 382 | |
| 383 | Now, trying to invoke (some other overload) of `operator*` |
| 384 | with, say, operand types `C` and `D` for which |
| 385 | `is_multipliable<C, D>::value` is `false` and |
| 386 | `mult_traits<C, D>::type` is not defined is an error on some |
| 387 | compilers. The SFINAE principle is not applied because the |
| 388 | invalid type occurs as an argument to another template. The |
| 389 | `lazy_enable_if` and `lazy_disable_if` templates (and their |
| 390 | `_c` versions) can be used in such situations: |
| 391 | |
| 392 | `` |
| 393 | template<class T, class U> |
| 394 | typename lazy_enable_if<is_multipliable<T, U>, |
| 395 | mult_traits<T, U> >::type |
| 396 | operator*(const T& t, const U& u) { ... } |
| 397 | |
| 398 | ``The second argument of `lazy_enable_if` must be a class type |
| 399 | that defines a nested type named `type` whenever the first |
| 400 | parameter (the condition) is true. |
| 401 | |
| 402 | [note Referring to one member type or static constant in a |
| 403 | traits class causes all of the members (type and static |
| 404 | constant) of that specialization to be instantiated. |
| 405 | Therefore, if your traits classes can sometimes contain invalid |
| 406 | types, you should use two distinct templates for describing the |
| 407 | conditions and the type mappings. In the above example, |
| 408 | `is_multipliable<T, U>::value` defines when |
| 409 | `mult_traits<T, U>::type` is valid.] |
| 410 | |
| 411 | [endsect] |
| 412 | |
| 413 | [section Compiler workarounds] |
| 414 | |
| 415 | Some compilers flag functions as ambiguous if the only |
| 416 | distinguishing factor is a different condition in an enabler |
| 417 | (even though the functions could never be ambiguous). For |
| 418 | example, some compilers (e.g. GCC 3.2) diagnose the following |
| 419 | two functions as ambiguous: |
| 420 | |
| 421 | `` |
| 422 | template <class T> |
| 423 | typename enable_if<boost::is_arithmetic<T>, T>::type |
| 424 | foo(T t); |
| 425 | |
| 426 | template <class T> |
| 427 | typename disable_if<boost::is_arithmetic<T>, T>::type |
| 428 | foo(T t); |
| 429 | `` |
| 430 | |
| 431 | Two workarounds can be applied: |
| 432 | |
| 433 | * Use an extra dummy parameter which disambiguates the |
| 434 | functions. Use a default value for it to hide the parameter |
| 435 | from the caller. For example: |
| 436 | `` |
| 437 | template <int> struct dummy { dummy(int) {} }; |
| 438 | |
| 439 | template <class T> |
| 440 | typename enable_if<boost::is_arithmetic<T>, T>::type |
| 441 | foo(T t, dummy<0> = 0); |
| 442 | |
| 443 | template <class T> |
| 444 | typename disable_if<boost::is_arithmetic<T>, T>::type |
| 445 | foo(T t, dummy<1> = 0); |
| 446 | `` |
| 447 | * Define the functions in different namespaces and bring them |
| 448 | into a common namespace with `using` declarations: |
| 449 | `` |
| 450 | namespace A { |
| 451 | template <class T> |
| 452 | typename enable_if<boost::is_arithmetic<T>, T>::type |
| 453 | foo(T t); |
| 454 | } |
| 455 | |
| 456 | namespace B { |
| 457 | template <class T> |
| 458 | typename disable_if<boost::is_arithmetic<T>, T>::type |
| 459 | foo(T t); |
| 460 | } |
| 461 | |
| 462 | using A::foo; |
| 463 | using B::foo; |
| 464 | `` |
| 465 | Note that the second workaround above cannot be used for |
| 466 | member templates. On the other hand, operators do not accept |
| 467 | extra arguments, which makes the first workaround unusable. |
| 468 | As the net effect, neither of the workarounds are of |
| 469 | assistance for templated operators that need to be defined as |
| 470 | member functions (assignment and subscript operators). |
| 471 | |
| 472 | [endsect] |
| 473 | |
| 474 | [endsect] |
| 475 | |
| 476 | [section Acknowledgements] |
| 477 | |
| 478 | We are grateful to Howard Hinnant, Jason Shirk, Paul |
| 479 | Mensonides, and Richard Smith whose findings have |
| 480 | influenced the library. |
| 481 | |
| 482 | [endsect] |
| 483 | |
| 484 | [section References] |
| 485 | |
| 486 | * [#REF1] \[1\] Jaakko J\u00E4rvi, Jeremiah Willcock, Howard |
| 487 | Hinnant, and Andrew Lumsdaine. Function overloading based on |
| 488 | arbitrary properties of types. /C++ Users Journal/, |
| 489 | 21(6):25--32, June 2003. |
| 490 | * [#REF2] \[2\] Jaakko J\u00E4rvi, Jeremiah Willcock, and |
| 491 | Andrew Lumsdaine. Concept-controlled polymorphism. In Frank |
| 492 | Pfennig and Yannis Smaragdakis, editors, /Generative |
| 493 | Programming and Component Engineering/, volume 2830 of |
| 494 | /LNCS/, pages 228--244. Springer Verlag, September 2003. |
| 495 | * [#REF3] \[3\] David Vandevoorde and Nicolai M. Josuttis. |
| 496 | /C++ Templates: The Complete Guide/. Addison-Wesley, 2002. |
| 497 | |
| 498 | [endsect] |
| 499 | |
| 500 | [endsect] |