BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_enableif.h
Go to the documentation of this file.
1/// @file bslmf_enableif.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmf_enableif.h -*-C++-*-
8#ifndef INCLUDED_BSLMF_ENABLEIF
9#define INCLUDED_BSLMF_ENABLEIF
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmf_enableif bslmf_enableif
15/// @brief Provide a utility to set up SFINAE conditions in type deduction.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmf
19/// @{
20/// @addtogroup bslmf_enableif
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmf_enableif-purpose"> Purpose</a>
25/// * <a href="#bslmf_enableif-classes"> Classes </a>
26/// * <a href="#bslmf_enableif-description"> Description </a>
27/// * <a href="#bslmf_enableif-visual-studio-workaround"> Visual Studio Workaround </a>
28/// * <a href="#bslmf_enableif-usage"> Usage </a>
29/// * <a href="#bslmf_enableif-example-1-implementing-a-simple-function-with-bsl-enable_if"> Example 1: Implementing a Simple Function with bsl::enable_if </a>
30/// * <a href="#bslmf_enableif-example-2-using-the-bsl-enable_if-result-type"> Example 2: Using the bsl::enable_if Result Type </a>
31/// * <a href="#bslmf_enableif-example-3-controlling-constructor-selection-with-bsl-enable_if"> Example 3: Controlling Constructor Selection with bsl::enable_if </a>
32///
33/// # Purpose {#bslmf_enableif-purpose}
34/// Provide a utility to set up SFINAE conditions in type deduction.
35///
36/// # Classes {#bslmf_enableif-classes}
37///
38/// - bsl::enable_if: standard meta-function to drop templates from overload sets
39/// - bsl::enable_if_t: alias to the return type of the meta-function
40/// - bslmf::EnableIf: meta-function to drop templates from overload sets
41///
42/// # Description {#bslmf_enableif-description}
43/// This component defines two meta-functions, `bsl::enable_if` and
44/// `bslmf::EnableIf`, both of which may be used to conditionally remove
45/// (potential) template instantiations as candidates for overload resolution by
46/// causing a deduced template instantiation to fail in a way compatible with
47/// the C++ SFINAE rules.
48///
49/// `bsl::enable_if` meets the requirements of the `enable_if` template defined
50/// in the C++11 standard [meta.trans.ptr], while `bslmf::EnableIf` was devised
51/// before `enable_if` was standardized.
52///
53/// The two meta-functions provide identical functionality. Both meta-functions
54/// provide a `typedef` `type` that is an alias to a (template parameter) type
55/// if a (template parameter) condition is `true`; otherwise, `type` is not
56/// provided.
57///
58/// Note that `bsl::enable_if` should be preferred over `bslmf::EnableIf`, and
59/// in general, should be used by new components.
60///
61/// ## Visual Studio Workaround {#bslmf_enableif-visual-studio-workaround}
62///
63///
64/// Because of a Visual Studio bug, described here:
65/// http://connect.microsoft.com/VisualStudio/feedback/details/332179/
66/// the Microsoft Visual Studio compiler may not correctly associate a function
67/// declaration that uses `bsl::enable_if` with that function's definition, if
68/// the definition is not inline to the declaration. This bug affects at least
69/// Visual Studio 2008 and 2010. The workaround is to implement functions using
70/// `bsl::enable_if` inline with their declaration.
71///
72/// ## Usage {#bslmf_enableif-usage}
73///
74///
75/// The following snippets of code illustrate basic use of the `bsl::enable_if`
76/// meta-function. We will demonstrate how to use this utility to control
77/// overload sets with three increasingly complex examples.
78///
79/// ### Example 1: Implementing a Simple Function with bsl::enable_if {#bslmf_enableif-example-1-implementing-a-simple-function-with-bsl-enable_if}
80///
81///
82/// Suppose that we want to implement a simple `swap` function template to
83/// exchange two arbitrary values, as if defined below:
84/// @code
85/// template<class t_TYPE>
86/// void DummySwap(t_TYPE& a, t_TYPE& b)
87/// // Exchange the values of the specified objects, 'a' and 'b'.
88/// {
89/// t_TYPE temp(a);
90/// a = b;
91/// b = temp;
92/// }
93/// @endcode
94/// However, we want to take advantage of member-swap methods supplied by user-
95/// defined types, so we define a trait that can be customized by a class
96/// implementer to indicate that their class supports an optimized member-swap
97/// method:
98/// @code
99/// template<class t_TYPE>
100/// struct HasMemberSwap : bsl::false_type {
101/// // This traits class indicates whether the (template parameter)
102/// // 't_TYPE' has a public 'swap' method to exchange values.
103/// };
104/// @endcode
105/// Now, we implement a generic `swap` function template that will invoke the
106/// member swap operation for any type that specialized our trait. The use of
107/// `bsl::enable_if` to declare the result type causes an attempt to deduce the
108/// type `t_TYPE` to fail unless the specified condition is `true`, and this
109/// falls under the "Substitution Failure Is Not An Error" (SFINAE) clause of
110/// the C++ standard, so the compiler will look for a more suitable overload
111/// rather than fail with an error. Note that we provide two overloaded
112/// declarations that appear to differ only in their return type, which would
113/// normally raise an ambiguity error. This works, and is in fact required, in
114/// this case as the "enable-if" conditions are mutually exclusive, so that only
115/// one overload will ever be present in an overload set. Also note that the
116/// `type` `typedef` of `bsl::enable_if` is an alias to `void` when the
117/// (template parameter) type is unspecified and the (template parameter)
118/// condition value is `true`.
119/// @code
120/// template<class t_TYPE>
121/// typename bsl::enable_if<HasMemberSwap<t_TYPE>::value>::type
122/// swap(t_TYPE& a, t_TYPE& b)
123/// {
124/// a.swap(b);
125/// }
126///
127/// template<class t_TYPE>
128/// typename bsl::enable_if< ! HasMemberSwap<t_TYPE>::value>::type
129/// swap(t_TYPE& a, t_TYPE& b)
130/// {
131/// t_TYPE temp(a);
132/// a = b;
133/// b = temp;
134/// }
135/// @endcode
136/// Next, we define a simple container template, that supports an optimized
137/// `swap` operation by merely swapping the internal pointer to the array of
138/// elements rather than exchanging each element:
139/// @code
140/// template<class t_TYPE>
141/// class MyContainer {
142/// // This is a simple container implementation for demonstration purposes
143/// // that is modeled after 'std::vector'.
144///
145/// // DATA
146/// t_TYPE *d_storage;
147/// size_t d_length;
148///
149/// // Copy operations are declared private and not defined.
150///
151/// // NOT IMPLEMENTED
152/// MyContainer(const MyContainer&);
153/// MyContainer& operator=(const MyContainer&);
154///
155/// public:
156/// MyContainer(const t_TYPE& value, int n);
157/// // Create a 'MyContainer' object having the specified 'n' copies of
158/// // the specified 'value'. The behavior is undefined unless
159/// // '0 <= n'.
160///
161/// ~MyContainer();
162/// // Destroy this container and all of its elements, reclaiming any
163/// // allocated memory.
164///
165/// // MANIPULATORS
166/// void swap(MyContainer &other);
167/// // Exchange the contents of 'this' container with those of the
168/// // specified 'other'. No memory will be allocated, and no
169/// // exceptions are thrown.
170///
171/// // ACCESSORS
172/// const t_TYPE& front() const;
173/// // Return a reference providing non-modifiable access to the first
174/// // element in this container. The behavior is undefined if this
175/// // container is empty.
176///
177/// size_t size() const;
178/// // Return the number of elements held by this container.
179/// };
180/// @endcode
181/// Then, we specialize our `HasMemberSwap` trait for this new container type.
182/// @code
183/// template<class t_TYPE>
184/// struct HasMemberSwap<MyContainer<t_TYPE> > : bsl::true_type {
185/// };
186/// @endcode
187/// Next, we implement the methods of this class:
188/// @code
189/// // CREATORS
190/// template<class t_TYPE>
191/// MyContainer<t_TYPE>::MyContainer(const t_TYPE& value, int n)
192/// : d_storage(new t_TYPE[n])
193/// , d_length(n)
194/// {
195/// for (int i = 0; i != n; ++i) {
196/// d_storage[i] = value;
197/// }
198/// }
199///
200/// template<class t_TYPE>
201/// MyContainer<t_TYPE>::~MyContainer()
202/// {
203/// delete[] d_storage;
204/// }
205///
206/// // MANIPULATORS
207/// template<class t_TYPE>
208/// void MyContainer<t_TYPE>::swap(MyContainer& other)
209/// {
210/// ::swap(d_storage, other.d_storage);
211/// ::swap(d_length, other.d_length);
212/// }
213///
214/// // ACCESSORS
215/// template<class t_TYPE>
216/// const t_TYPE& MyContainer<t_TYPE>::front() const
217/// {
218/// return d_storage[0];
219/// }
220///
221/// template<class t_TYPE>
222/// size_t MyContainer<t_TYPE>::size() const
223/// {
224/// return d_length;
225/// }
226/// @endcode
227/// Finally, we can test that the member-`swap` method is called by the generic
228/// `swap` function. Note that the following code will not compile unless the
229/// member-function `swap` is used, as the copy constructor and assignment
230/// operator for the `MyContainer` class template are declared as `private`.
231/// @code
232/// void TestSwap()
233/// {
234/// MyContainer<int> x(3, 14);
235/// MyContainer<int> y(2, 78);
236/// assert(14 == x.size());
237/// assert( 3 == x.front());
238/// assert(78 == y.size());
239/// assert( 2 == y.front());
240///
241/// swap(x, y);
242///
243/// assert(78 == x.size());
244/// assert( 2 == x.front());
245/// assert(14 == y.size());
246/// assert( 3 == y.front());
247/// }
248/// @endcode
249///
250/// ### Example 2: Using the bsl::enable_if Result Type {#bslmf_enableif-example-2-using-the-bsl-enable_if-result-type}
251///
252///
253/// For the next example, we will demonstrate the use of the second template
254/// parameter in the `bsl::enable_if` template, which serves as the "result"
255/// type if the test condition passes. Suppose that we want to write a generic
256/// function to allow us to cast between pointers of different types. If the
257/// types are polymorphic, we can use @ref dynamic_cast to potentially cast between
258/// two seemingly unrelated types. However, if either type is not polymorphic
259/// then the attempt to use @ref dynamic_cast would be a compile-time failure, and
260/// we must use @ref static_cast instead.
261/// @code
262/// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
263/// @endcode
264/// Note that if the current compiler supports alias templates C++11 feature, we
265/// can use `bsl::enable_if_t` alias to the "result" type of `bsl::enable_if`
266/// meta-function, that avoids the `::type` suffix and `typename` prefix in the
267/// declaration of the function return type.
268/// @code
269/// template<class t_TO, class t_FROM>
270/// bsl::enable_if_t<bsl::is_polymorphic<t_FROM>::value &&
271/// bsl::is_polymorphic<t_TO >::value, t_TO> *
272/// #else
273/// template<class t_TO, class t_FROM>
274/// typename bsl::enable_if<bsl::is_polymorphic<t_FROM>::value &&
275/// bsl::is_polymorphic<t_TO>::value,
276/// t_TO>::type *
277/// #endif
278/// smart_cast(t_FROM *from)
279/// // Return a pointer to the specified 'TO' type if the specified 'from'
280/// // pointer refers to an object whose complete class publicly derives,
281/// // directly or indirectly, from 'TO', and a null pointer otherwise.
282/// {
283/// return dynamic_cast<t_TO *>(from);
284/// }
285///
286/// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
287/// template<class t_TO, class t_FROM>
288/// bsl::enable_if_t<not(bsl::is_polymorphic<t_FROM>::value &&
289/// bsl::is_polymorphic<t_TO >::value), t_TO> *
290/// #else
291/// template<class t_TO, class t_FROM>
292/// typename bsl::enable_if<not(bsl::is_polymorphic<t_FROM>::value &&
293/// bsl::is_polymorphic<t_TO>::value),
294/// t_TO>::type *
295/// #endif
296/// smart_cast(t_FROM *from)
297/// // Return the specified 'from' pointer value cast as a pointer to type
298/// // 'TO'. The behavior is undefined unless such a conversion is valid.
299/// {
300/// return static_cast<t_TO *>(from);
301/// }
302/// @endcode
303/// Next, we define a small number of classes to demonstrate that this casting
304/// utility works correctly:
305/// @code
306/// class A {
307/// // Sample non-polymorphic type
308///
309/// public:
310/// ~A() {}
311/// };
312///
313/// class B {
314/// // Sample polymorphic base-type
315///
316/// public:
317/// virtual ~B() {}
318/// };
319///
320/// class C {
321/// // Sample polymorphic base-type
322///
323/// public:
324/// virtual ~C() {}
325/// };
326///
327/// class ABC : public A, public B, public C {
328/// // Most-derived example class using multiple bases in order to
329/// // demonstrate cross-casting.
330/// };
331/// @endcode
332/// Finally, we demonstrate the correct behavior of the @ref smart_cast utility:
333/// @code
334/// void TestSmartCast()
335/// {
336/// ABC object;
337/// ABC *pABC = &object;
338/// A *pA = &object;
339/// B *pB = &object;
340/// C *pC = &object;
341///
342/// A *pA2 = smart_cast<A>(pABC);
343/// B *pB2 = smart_cast<B>(pC);
344/// C *pC2 = smart_cast<C>(pB);
345///
346/// (void) pA;
347///
348/// assert(&object == pA2);
349/// assert(&object == pB2);
350/// assert(&object == pC2);
351///
352/// // These lines would fail to compile
353/// // A *pA3 = smart_cast<A>(pB);
354/// // C *pC3 = smart_cast<C>(pA);
355/// }
356/// @endcode
357///
358/// ### Example 3: Controlling Constructor Selection with bsl::enable_if {#bslmf_enableif-example-3-controlling-constructor-selection-with-bsl-enable_if}
359///
360///
361/// The final example demonstrates controlling the selection of a constructor
362/// template in a class with (potentially) many constructors. We define a
363/// simple container template based on `std::vector` that illustrates a problem
364/// that may occur when trying to call the constructor the user expects. For
365/// this example, assume we are trying to create a `vector<int>` with `42`
366/// copies of the value `13`. When we pass the literal values `42` and `13` to
367/// the compiler, the "best" candidate constructor should be the template
368/// constructor that takes two arguments of the same kind, deducing that type to
369/// be `int`. Unfortunately, that constructor expects those values to be of an
370/// iterator type, forming a valid range. We need to avoid calling this
371/// constructor unless the deduced type really is an iterator, otherwise a
372/// compile-error will occur trying to instantiate that constructor with an
373/// incompatible argument type. We use `bsl::enable_if` to create a deduction
374/// context where SFINAE can kick in. Note that we cannot deduce the `::type`
375/// result of a meta-function, and there is no result type (as with a regular
376/// function) to decorate, so we add an extra dummy argument using a pointer
377/// type (produced from `bsl::enable_if::type`) with a default null argument:
378/// @code
379/// template<class t_TYPE>
380/// class MyVector {
381/// // This is a simple container implementation for demonstration purposes
382/// // that is modeled after 'std::vector'.
383///
384/// // DATA
385/// t_TYPE *d_storage;
386/// size_t d_length;
387///
388/// // NOT IMPLEMENTED
389/// MyVector(const MyVector&);
390/// MyVector& operator=(const MyVector&);
391///
392/// public:
393/// // CREATORS
394/// MyVector(const t_TYPE& value, int n);
395/// // Create a 'MyVector' object having the specified 'n' copies of
396/// // the specified 'value'. The behavior is undefined unless
397/// // '0 <= n'.
398///
399/// template<class t_FORWARD_ITERATOR>
400/// MyVector(t_FORWARD_ITERATOR first, t_FORWARD_ITERATOR last,
401/// typename bsl::enable_if<
402/// bsl::is_pointer<t_FORWARD_ITERATOR>::value>::type * = 0)
403/// // Create a 'MyVector' object having the same sequence of values as
404/// // found in the range described by the specified iterators
405/// // '[first, last)'. The behavior is undefined unless 'first' and
406/// // 'last' refer to a sequence of values of the (template parameter)
407/// // type 't_TYPE' where 'first' is at a position at or before
408/// // 'last'. Note that this function is currently defined inline to
409/// // work around an issue with the Microsoft Visual Studio compiler.
410/// {
411/// d_length = 0;
412/// for (t_FORWARD_ITERATOR cursor = first; cursor != last; ++cursor) {
413/// ++d_length;
414/// }
415///
416/// d_storage = new t_TYPE[d_length];
417/// for (size_t i = 0; i != d_length; ++i) {
418/// d_storage[i] = *first;
419/// ++first;
420/// }
421/// }
422///
423/// ~MyVector();
424/// // Destroy this container and all of its elements, reclaiming any
425/// // allocated memory.
426///
427/// // ACCESSORS
428/// const t_TYPE& operator[](int index) const;
429/// // Return a reference providing non-modifiable access to the
430/// // element held by this container at the specified 'index'. The
431/// // behavior is undefined unless 'index < size()'.
432///
433/// size_t size() const;
434/// // Return the number of elements held by this container.
435/// };
436/// @endcode
437/// Note that there is no easy test for whether a type is an iterator, so we
438/// assume that any attempt to call a constructor with two arguments that are
439/// not fundamental (such as `int`) must be passing iterators. Now that we have
440/// defined the class template, we implement its methods:
441/// @code
442/// template<class t_TYPE>
443/// MyVector<t_TYPE>::MyVector(const t_TYPE& value, int n)
444/// : d_storage(new t_TYPE[n])
445/// , d_length(n)
446/// {
447/// for (int i = 0; i != n; ++i) {
448/// d_storage[i] = value;
449/// }
450/// }
451///
452/// template<class t_TYPE>
453/// MyVector<t_TYPE>::~MyVector()
454/// {
455/// delete[] d_storage;
456/// }
457///
458/// // ACCESSORS
459/// template<class t_TYPE>
460/// const t_TYPE& MyVector<t_TYPE>::operator[](int index) const
461/// {
462/// return d_storage[index];
463/// }
464///
465/// template<class t_TYPE>
466/// size_t MyVector<t_TYPE>::size() const
467/// {
468/// return d_length;
469/// }
470/// @endcode
471/// Finally, we demonstrate that the correct constructors are called when
472/// invoked with appropriate arguments:
473/// @code
474/// void TestContainerConstructor()
475/// {
476/// const unsigned int TEST_DATA[] = { 1, 2, 3, 4, 5 };
477///
478/// const MyVector<unsigned int> x(&TEST_DATA[0], &TEST_DATA[5]);
479/// const MyVector<unsigned int> y(13, 42);
480///
481/// assert(5 == x.size());
482/// for (int i = 0; i != 5; ++i) {
483/// assert(TEST_DATA[i] == x[i]);
484/// }
485///
486/// assert(42 == y.size());
487/// for (int i = 0; i != 42; ++i) {
488/// assert(13 == y[i]);
489/// }
490/// }
491/// @endcode
492/// @}
493/** @} */
494/** @} */
495
496/** @addtogroup bsl
497 * @{
498 */
499/** @addtogroup bslmf
500 * @{
501 */
502/** @addtogroup bslmf_enableif
503 * @{
504 */
505
506#include <bslscm_version.h>
507
509
510namespace bsl {
511
512 // ================
513 // struct enable_if
514 // ================
515
516/// This `struct` template implements the `enable_if` meta-function defined
517/// in the C++11 standard [meta.trans.ptr]. This `struct` template provides
518/// a `typedef` `type` that is an alias to the (template parameter) `t_TYPE`
519/// if the (template parameter) `t_COND` is `true`; otherwise, `type` is not
520/// provided. If `t_TYPE` is not specified, it is set to `void`. Note that
521/// this generic default template provides `type` for when `t_COND` is
522/// `true`; a template specialization is provided (below) that omits `type`
523/// for when `t_COND` is `false`.
524template <bool t_COND, class t_TYPE = void>
525struct enable_if {
526
527 /// This `typedef` is an alias to the (template parameter) `t_TYPE`.
528 typedef t_TYPE type;
529};
530
531 // ===============================
532 // struct enable_if<false, t_TYPE>
533 // ===============================
534
535/// This partial specialization of `enable_if`, for when the (template
536/// parameter) `t_COND` is `false`, guarantees that no `typedef` `type` is
537/// supplied. Note that this class definition is intentionally empty.
538template <class t_TYPE>
539struct enable_if<false, t_TYPE> {
540};
541
542#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
543
544// ALIASES
545
546/// `enable_if_t` is an alias to the return type of the `bsl::enable_if`
547/// meta-function. Note, that the `enable_if_t` avoids the `::type` suffix
548/// and `typename` prefix when we want to use the result of the
549/// meta-function in templates.
550template <bool t_COND, class t_TYPE = void>
551using enable_if_t = typename enable_if<t_COND, t_TYPE>::type;
552
553#endif // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
554
555} // close namespace bsl
556
557
558
559namespace bslmf {
560
561 // ===============
562 // struct EnableIf
563 // ===============
564
565/// This `struct` template implements a meta-function that provides a
566/// `typedef` `type` that is an alias to the (template parameter) `t_TYPE`
567/// if the (template parameter) `t_COND` is `true`; otherwise, `type` is not
568/// provided. If `t_TYPE` is not specified, it is set to `void`. Note that
569/// this generic default template provides `type` for when `t_COND` is
570/// `true`; a template specialization is provided (below) that omits `type`
571/// for when `t_COND` is `false`.
572///
573/// Also note that although this `struct` is functionally identical to
574/// `bsl::enable_if`, the use of `bsl::enable_if` should be preferred.
575template <bool t_COND, class t_TYPE = void>
576struct EnableIf {
577
578 /// This `typedef` is an alias to the (template parameter) `t_TYPE`.
579 typedef t_TYPE type;
580};
581
582/// This partial specialization of `EnableIf`, for when the (template
583/// parameter) `t_COND` is `false`, guarantees that no `typedef` `type` is
584/// supplied. Note that this class definition is intentionally empty.
585template <class t_TYPE>
586struct EnableIf<false, t_TYPE> {
587};
588
589} // close package namespace
590
591
592#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
593// ============================================================================
594// BACKWARD COMPATIBILITY
595// ============================================================================
596
597#ifdef bslmf_EnableIf
598#undef bslmf_EnableIf
599#endif
600/// This alias is defined for backward compatibility.
601#define bslmf_EnableIf bslmf::EnableIf
602#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
603
604#endif
605
606// ----------------------------------------------------------------------------
607// Copyright 2013 Bloomberg Finance L.P.
608//
609// Licensed under the Apache License, Version 2.0 (the "License");
610// you may not use this file except in compliance with the License.
611// You may obtain a copy of the License at
612//
613// http://www.apache.org/licenses/LICENSE-2.0
614//
615// Unless required by applicable law or agreed to in writing, software
616// distributed under the License is distributed on an "AS IS" BASIS,
617// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
618// See the License for the specific language governing permissions and
619// limitations under the License.
620// ----------------------------- END-OF-FILE ----------------------------------
621
622/** @} */
623/** @} */
624/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlb_printmethods.h:283
Definition bdlbb_blob.h:576
Definition bslmf_enableif.h:525
t_TYPE type
This typedef is an alias to the (template parameter) t_TYPE.
Definition bslmf_enableif.h:528
Definition bslmf_enableif.h:576
t_TYPE type
This typedef is an alias to the (template parameter) t_TYPE.
Definition bslmf_enableif.h:579