BDE 4.39.x 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/// private:
152/// // NOT IMPLEMENTED
153/// MyContainer(const MyContainer&);
154/// MyContainer& operator=(const MyContainer&);
155///
156/// public:
157/// MyContainer(const t_TYPE& value, int n);
158/// // Create a 'MyContainer' object having the specified 'n' copies of
159/// // the specified 'value'. The behavior is undefined unless
160/// // '0 <= n'.
161///
162/// ~MyContainer();
163/// // Destroy this container and all of its elements, reclaiming any
164/// // allocated memory.
165///
166/// // MANIPULATORS
167/// void swap(MyContainer &other);
168/// // Exchange the contents of 'this' container with those of the
169/// // specified 'other'. No memory will be allocated, and no
170/// // exceptions are thrown.
171///
172/// // ACCESSORS
173/// const t_TYPE& front() const;
174/// // Return a reference providing non-modifiable access to the first
175/// // element in this container. The behavior is undefined if this
176/// // container is empty.
177///
178/// size_t size() const;
179/// // Return the number of elements held by this container.
180/// };
181/// @endcode
182/// Then, we specialize our `HasMemberSwap` trait for this new container type.
183/// @code
184/// template<class t_TYPE>
185/// struct HasMemberSwap<MyContainer<t_TYPE> > : bsl::true_type {
186/// };
187/// @endcode
188/// Next, we implement the methods of this class:
189/// @code
190/// // CREATORS
191/// template<class t_TYPE>
192/// MyContainer<t_TYPE>::MyContainer(const t_TYPE& value, int n)
193/// : d_storage(new t_TYPE[n])
194/// , d_length(n)
195/// {
196/// for (int i = 0; i != n; ++i) {
197/// d_storage[i] = value;
198/// }
199/// }
200///
201/// template<class t_TYPE>
202/// MyContainer<t_TYPE>::~MyContainer()
203/// {
204/// delete[] d_storage;
205/// }
206///
207/// // MANIPULATORS
208/// template<class t_TYPE>
209/// void MyContainer<t_TYPE>::swap(MyContainer& other)
210/// {
211/// ::swap(d_storage, other.d_storage);
212/// ::swap(d_length, other.d_length);
213/// }
214///
215/// // ACCESSORS
216/// template<class t_TYPE>
217/// const t_TYPE& MyContainer<t_TYPE>::front() const
218/// {
219/// return d_storage[0];
220/// }
221///
222/// template<class t_TYPE>
223/// size_t MyContainer<t_TYPE>::size() const
224/// {
225/// return d_length;
226/// }
227/// @endcode
228/// Finally, we can test that the member-`swap` method is called by the generic
229/// `swap` function. Note that the following code will not compile unless the
230/// member-function `swap` is used, as the copy constructor and assignment
231/// operator for the `MyContainer` class template are declared as `private`.
232/// @code
233/// void TestSwap()
234/// {
235/// MyContainer<int> x(3, 14);
236/// MyContainer<int> y(2, 78);
237/// assert(14 == x.size());
238/// assert( 3 == x.front());
239/// assert(78 == y.size());
240/// assert( 2 == y.front());
241///
242/// swap(x, y);
243///
244/// assert(78 == x.size());
245/// assert( 2 == x.front());
246/// assert(14 == y.size());
247/// assert( 3 == y.front());
248/// }
249/// @endcode
250///
251/// ### Example 2: Using the bsl::enable_if Result Type {#bslmf_enableif-example-2-using-the-bsl-enable_if-result-type}
252///
253///
254/// For the next example, we will demonstrate the use of the second template
255/// parameter in the `bsl::enable_if` template, which serves as the "result"
256/// type if the test condition passes. Suppose that we want to write a generic
257/// function to allow us to cast between pointers of different types. If the
258/// types are polymorphic, we can use @ref dynamic_cast to potentially cast between
259/// two seemingly unrelated types. However, if either type is not polymorphic
260/// then the attempt to use @ref dynamic_cast would be a compile-time failure, and
261/// we must use @ref static_cast instead.
262/// @code
263/// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
264/// @endcode
265/// Note that if the current compiler supports alias templates C++11 feature, we
266/// can use `bsl::enable_if_t` alias to the "result" type of `bsl::enable_if`
267/// meta-function, that avoids the `::type` suffix and `typename` prefix in the
268/// declaration of the function return type.
269/// @code
270/// template<class t_TO, class t_FROM>
271/// bsl::enable_if_t<bsl::is_polymorphic<t_FROM>::value &&
272/// bsl::is_polymorphic<t_TO >::value, t_TO> *
273/// #else
274/// template<class t_TO, class t_FROM>
275/// typename bsl::enable_if<bsl::is_polymorphic<t_FROM>::value &&
276/// bsl::is_polymorphic<t_TO>::value,
277/// t_TO>::type *
278/// #endif
279/// smart_cast(t_FROM *from)
280/// // Return a pointer to the specified 'TO' type if the specified 'from'
281/// // pointer refers to an object whose complete class publicly derives,
282/// // directly or indirectly, from 'TO', and a null pointer otherwise.
283/// {
284/// return dynamic_cast<t_TO *>(from);
285/// }
286///
287/// #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
288/// template<class t_TO, class t_FROM>
289/// bsl::enable_if_t<not(bsl::is_polymorphic<t_FROM>::value &&
290/// bsl::is_polymorphic<t_TO >::value), t_TO> *
291/// #else
292/// template<class t_TO, class t_FROM>
293/// typename bsl::enable_if<not(bsl::is_polymorphic<t_FROM>::value &&
294/// bsl::is_polymorphic<t_TO>::value),
295/// t_TO>::type *
296/// #endif
297/// smart_cast(t_FROM *from)
298/// // Return the specified 'from' pointer value cast as a pointer to type
299/// // 'TO'. The behavior is undefined unless such a conversion is valid.
300/// {
301/// return static_cast<t_TO *>(from);
302/// }
303/// @endcode
304/// Next, we define a small number of classes to demonstrate that this casting
305/// utility works correctly:
306/// @code
307/// class A {
308/// // Sample non-polymorphic type
309///
310/// public:
311/// ~A() {}
312/// };
313///
314/// class B {
315/// // Sample polymorphic base-type
316///
317/// public:
318/// virtual ~B() {}
319/// };
320///
321/// class C {
322/// // Sample polymorphic base-type
323///
324/// public:
325/// virtual ~C() {}
326/// };
327///
328/// class ABC : public A, public B, public C {
329/// // Most-derived example class using multiple bases in order to
330/// // demonstrate cross-casting.
331/// };
332/// @endcode
333/// Finally, we demonstrate the correct behavior of the @ref smart_cast utility:
334/// @code
335/// void TestSmartCast()
336/// {
337/// ABC object;
338/// ABC *pABC = &object;
339/// A *pA = &object;
340/// B *pB = &object;
341/// C *pC = &object;
342///
343/// A *pA2 = smart_cast<A>(pABC);
344/// B *pB2 = smart_cast<B>(pC);
345/// C *pC2 = smart_cast<C>(pB);
346///
347/// (void) pA;
348///
349/// assert(&object == pA2);
350/// assert(&object == pB2);
351/// assert(&object == pC2);
352///
353/// // These lines would fail to compile
354/// // A *pA3 = smart_cast<A>(pB);
355/// // C *pC3 = smart_cast<C>(pA);
356/// }
357/// @endcode
358///
359/// ### Example 3: Controlling Constructor Selection with bsl::enable_if {#bslmf_enableif-example-3-controlling-constructor-selection-with-bsl-enable_if}
360///
361///
362/// The final example demonstrates controlling the selection of a constructor
363/// template in a class with (potentially) many constructors. We define a
364/// simple container template based on `std::vector` that illustrates a problem
365/// that may occur when trying to call the constructor the user expects. For
366/// this example, assume we are trying to create a `vector<int>` with `42`
367/// copies of the value `13`. When we pass the literal values `42` and `13` to
368/// the compiler, the "best" candidate constructor should be the template
369/// constructor that takes two arguments of the same kind, deducing that type to
370/// be `int`. Unfortunately, that constructor expects those values to be of an
371/// iterator type, forming a valid range. We need to avoid calling this
372/// constructor unless the deduced type really is an iterator, otherwise a
373/// compile-error will occur trying to instantiate that constructor with an
374/// incompatible argument type. We use `bsl::enable_if` to create a deduction
375/// context where SFINAE can kick in. Note that we cannot deduce the `::type`
376/// result of a meta-function, and there is no result type (as with a regular
377/// function) to decorate, so we add an extra dummy argument using a pointer
378/// type (produced from `bsl::enable_if::type`) with a default null argument:
379/// @code
380/// template<class t_TYPE>
381/// class MyVector {
382/// // This is a simple container implementation for demonstration purposes
383/// // that is modeled after 'std::vector'.
384///
385/// // DATA
386/// t_TYPE *d_storage;
387/// size_t d_length;
388///
389/// private:
390/// // NOT IMPLEMENTED
391/// MyVector(const MyVector&);
392/// MyVector& operator=(const MyVector&);
393///
394/// public:
395/// // CREATORS
396/// MyVector(const t_TYPE& value, int n);
397/// // Create a 'MyVector' object having the specified 'n' copies of
398/// // the specified 'value'. The behavior is undefined unless
399/// // '0 <= n'.
400///
401/// template<class t_FORWARD_ITERATOR>
402/// MyVector(t_FORWARD_ITERATOR first, t_FORWARD_ITERATOR last,
403/// typename bsl::enable_if<
404/// bsl::is_pointer<t_FORWARD_ITERATOR>::value>::type * = 0)
405/// // Create a 'MyVector' object having the same sequence of values as
406/// // found in the range described by the specified iterators
407/// // '[first, last)'. The behavior is undefined unless 'first' and
408/// // 'last' refer to a sequence of values of the (template parameter)
409/// // type 't_TYPE' where 'first' is at a position at or before
410/// // 'last'. Note that this function is currently defined inline to
411/// // work around an issue with the Microsoft Visual Studio compiler.
412/// {
413/// d_length = 0;
414/// for (t_FORWARD_ITERATOR cursor = first; cursor != last; ++cursor) {
415/// ++d_length;
416/// }
417///
418/// d_storage = new t_TYPE[d_length];
419/// for (size_t i = 0; i != d_length; ++i) {
420/// d_storage[i] = *first;
421/// ++first;
422/// }
423/// }
424///
425/// ~MyVector();
426/// // Destroy this container and all of its elements, reclaiming any
427/// // allocated memory.
428///
429/// // ACCESSORS
430/// const t_TYPE& operator[](int index) const;
431/// // Return a reference providing non-modifiable access to the
432/// // element held by this container at the specified 'index'. The
433/// // behavior is undefined unless 'index < size()'.
434///
435/// size_t size() const;
436/// // Return the number of elements held by this container.
437/// };
438/// @endcode
439/// Note that there is no easy test for whether a type is an iterator, so we
440/// assume that any attempt to call a constructor with two arguments that are
441/// not fundamental (such as `int`) must be passing iterators. Now that we have
442/// defined the class template, we implement its methods:
443/// @code
444/// template<class t_TYPE>
445/// MyVector<t_TYPE>::MyVector(const t_TYPE& value, int n)
446/// : d_storage(new t_TYPE[n])
447/// , d_length(n)
448/// {
449/// for (int i = 0; i != n; ++i) {
450/// d_storage[i] = value;
451/// }
452/// }
453///
454/// template<class t_TYPE>
455/// MyVector<t_TYPE>::~MyVector()
456/// {
457/// delete[] d_storage;
458/// }
459///
460/// // ACCESSORS
461/// template<class t_TYPE>
462/// const t_TYPE& MyVector<t_TYPE>::operator[](int index) const
463/// {
464/// return d_storage[index];
465/// }
466///
467/// template<class t_TYPE>
468/// size_t MyVector<t_TYPE>::size() const
469/// {
470/// return d_length;
471/// }
472/// @endcode
473/// Finally, we demonstrate that the correct constructors are called when
474/// invoked with appropriate arguments:
475/// @code
476/// void TestContainerConstructor()
477/// {
478/// const unsigned int TEST_DATA[] = { 1, 2, 3, 4, 5 };
479///
480/// const MyVector<unsigned int> x(&TEST_DATA[0], &TEST_DATA[5]);
481/// const MyVector<unsigned int> y(13, 42);
482///
483/// assert(5 == x.size());
484/// for (int i = 0; i != 5; ++i) {
485/// assert(TEST_DATA[i] == x[i]);
486/// }
487///
488/// assert(42 == y.size());
489/// for (int i = 0; i != 42; ++i) {
490/// assert(13 == y[i]);
491/// }
492/// }
493/// @endcode
494/// @}
495/** @} */
496/** @} */
497
498/** @addtogroup bsl
499 * @{
500 */
501/** @addtogroup bslmf
502 * @{
503 */
504/** @addtogroup bslmf_enableif
505 * @{
506 */
507
508#include <bslscm_version.h>
509
511
512namespace bsl {
513
514 // ================
515 // struct enable_if
516 // ================
517
518/// This `struct` template implements the `enable_if` meta-function defined
519/// in the C++11 standard [meta.trans.ptr]. This `struct` template provides
520/// a `typedef` `type` that is an alias to the (template parameter) `t_TYPE`
521/// if the (template parameter) `t_COND` is `true`; otherwise, `type` is not
522/// provided. If `t_TYPE` is not specified, it is set to `void`.
523///
524/// \note Note that this generic default template provides `type` for when `t_COND` is
525/// `true`; a template specialization is provided (below) that omits `type`
526/// for when `t_COND` is `false`.
527///
528/// See @ref bslmf_enableif
529template <bool t_COND, class t_TYPE = void>
530struct enable_if {
531
532 /// This `typedef` is an alias to the (template parameter) `t_TYPE`.
533 typedef t_TYPE type;
534};
535
536 // ===============================
537 // struct enable_if<false, t_TYPE>
538 // ===============================
539
540/// This partial specialization of `enable_if`, for when the (template
541/// parameter) `t_COND` is `false`, guarantees that no `typedef` `type` is supplied.
542///
543/// \note Note that this class definition is intentionally empty.
544template <class t_TYPE>
545struct enable_if<false, t_TYPE> {
546};
547
548#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
549
550// ALIASES
551
552/// @ref enable_if_t is an alias to the return type of the `bsl::enable_if`
553/// meta-function. Note, that the @ref enable_if_t avoids the `::type` suffix
554/// and `typename` prefix when we want to use the result of the
555/// meta-function in templates.
556template <bool t_COND, class t_TYPE = void>
557using enable_if_t = typename enable_if<t_COND, t_TYPE>::type;
558
559#endif // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
560
561} // close namespace bsl
562
563
564
565namespace bslmf {
566
567 // ===============
568 // struct EnableIf
569 // ===============
570
571/// This `struct` template implements a meta-function that provides a
572/// `typedef` `type` that is an alias to the (template parameter) `t_TYPE`
573/// if the (template parameter) `t_COND` is `true`; otherwise, `type` is not
574/// provided. If `t_TYPE` is not specified, it is set to `void`.
575///
576/// \note Note that this generic default template provides `type` for when `t_COND` is
577/// `true`; a template specialization is provided (below) that omits `type`
578/// for when `t_COND` is `false`.
579///
580/// Also note that although this `struct` is functionally identical to
581/// `bsl::enable_if`, the use of `bsl::enable_if` should be preferred.
582///
583/// See @ref bslmf_enableif
584template <bool t_COND, class t_TYPE = void>
585struct EnableIf {
586
587 /// This `typedef` is an alias to the (template parameter) `t_TYPE`.
588 typedef t_TYPE type;
589};
590
591/// This partial specialization of `EnableIf`, for when the (template
592/// parameter) `t_COND` is `false`, guarantees that no `typedef` `type` is supplied.
593///
594/// \note Note that this class definition is intentionally empty.
595template <class t_TYPE>
596struct EnableIf<false, t_TYPE> {
597};
598
599} // close package namespace
600
601
602#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
603// ============================================================================
604// BACKWARD COMPATIBILITY
605// ============================================================================
606
607#ifdef bslmf_EnableIf
608#undef bslmf_EnableIf
609#endif
610/// This alias is defined for backward compatibility.
611#define bslmf_EnableIf bslmf::EnableIf
612#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
613
614#endif
615
616// ----------------------------------------------------------------------------
617// Copyright 2013 Bloomberg Finance L.P.
618//
619// Licensed under the Apache License, Version 2.0 (the "License");
620// you may not use this file except in compliance with the License.
621// You may obtain a copy of the License at
622//
623// http://www.apache.org/licenses/LICENSE-2.0
624//
625// Unless required by applicable law or agreed to in writing, software
626// distributed under the License is distributed on an "AS IS" BASIS,
627// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
628// See the License for the specific language governing permissions and
629// limitations under the License.
630// ----------------------------- END-OF-FILE ----------------------------------
631
632/** @} */
633/** @} */
634/** @} */
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlat_valuetypefunctions.h:939
Definition bdlbb_blob.h:579
Definition bslmf_enableif.h:530
t_TYPE type
This typedef is an alias to the (template parameter) t_TYPE.
Definition bslmf_enableif.h:533
Definition bslmf_enableif.h:585
t_TYPE type
This typedef is an alias to the (template parameter) t_TYPE.
Definition bslmf_enableif.h:588