• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]
501