]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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] |