BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_selecttrait.h
Go to the documentation of this file.
1/// @file bslmf_selecttrait.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmf_selecttrait.h -*-C++-*-
8#ifndef INCLUDED_BSLMF_SELECTTRAIT
9#define INCLUDED_BSLMF_SELECTTRAIT
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmf_selecttrait bslmf_selecttrait
15/// @brief Provide clean compile-time dispatch based on multiple traits
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmf
19/// @{
20/// @addtogroup bslmf_selecttrait
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmf_selecttrait-purpose"> Purpose</a>
25/// * <a href="#bslmf_selecttrait-classes"> Classes </a>
26/// * <a href="#bslmf_selecttrait-description"> Description </a>
27/// * <a href="#bslmf_selecttrait-usage"> Usage </a>
28/// * <a href="#bslmf_selecttrait-example-1-dispatch-on-traits"> Example 1: Dispatch On Traits </a>
29///
30/// # Purpose {#bslmf_selecttrait-purpose}
31/// Provide clean compile-time dispatch based on multiple traits
32///
33/// # Classes {#bslmf_selecttrait-classes}
34///
35/// - bslmf::SelectTrait Template that selects the first of multiple traits
36/// - bslmf::SelectTraitCase Template that identifies a selected trait
37///
38/// @see
39///
40/// # Description {#bslmf_selecttrait-description}
41///
42///
43/// ## Usage {#bslmf_selecttrait-usage}
44///
45///
46/// This section illustrates the intended usage of this component.
47///
48/// ### Example 1: Dispatch On Traits {#bslmf_selecttrait-example-1-dispatch-on-traits}
49///
50///
51/// We would like to create a function template,
52/// `ScalarPrimitives::copyConstruct`, that takes an original object and an
53/// allocator constructs a copy of `original` using the most efficient valid
54/// mechanism. The function should take into account that the original type
55/// might be bitwise copyable, or have an allocator that can be different in
56/// the copy than in the original object, or that the original might be a pair
57/// type, where the correct method of copying `first` and `second` is
58/// (recursively) governed by the same concerns.
59///
60/// The old (legacy) `bsls::HasTrait` mechanism has a clumsy mechanism for
61/// dispatching on multiple traits at once. For example, the
62/// `bslalg::scalarprimitives::copyConstruct`, function uses four different
63/// implementations, depending on the traits of the object being copied. The
64/// existing code looks like this:
65/// @code
66/// template <class TARGET_TYPE>
67/// inline
68/// void
69/// ScalarPrimitives::copyConstruct(TARGET_TYPE *address,
70/// const TARGET_TYPE& original,
71/// bslma::Allocator *allocator)
72/// {
73/// BSLS_ASSERT_SAFE(address);
74///
75/// enum {
76/// VALUE = HasTrait<TARGET_TYPE,
77/// TypeTraitUsesBslmaAllocator
78/// >::value ? Imp::USES_BSLMA_ALLOCATOR_TRAITS
79/// : HasTrait<TARGET_TYPE,
80/// TypeTraitBitwiseCopyable
81/// >::value ? Imp::BITWISE_COPYABLE_TRAITS
82/// : HasTrait<TARGET_TYPE,
83/// TypeTraitPair
84/// >::value ? Imp::PAIR_TRAITS
85/// : Imp::NIL_TRAITS
86/// };
87/// Imp::copyConstruct(address, original, allocator,
88/// (bsl::integral_constant<int, VALUE>*)0);
89/// }
90/// @endcode
91/// We would like to replace the cumbersome chain of `?:` operations with a
92/// clean mechanism for producing one of four different types based on the
93/// first matching trait.
94///
95/// First, we create three traits metafunctions to replace the three legacy
96/// traits used above:
97/// @code
98/// template <class t_TYPE> struct UsesBslmaAllocator : bsl::false_type { };
99/// template <class t_TYPE> struct IsBitwiseCopyable : bsl::false_type { };
100/// template <class t_TYPE> struct IsPair : bsl::false_type { };
101/// @endcode
102/// Note that these definitions are simplified to avoid excess dependencies; A
103/// proper traits definition would inherit from `bslmf::DetectNestedTrait`
104/// instead of from `bsl::false_type`.
105///
106/// Next, we forward-declare `bslma::Allocator` and
107/// `bslalg::scalarprimitives::copyConstruct`:
108/// @code
109/// namespace bslma { class Allocator; }
110///
111/// namespace bslalg {
112/// struct ScalarPrimitives {
113/// template <class TARGET_TYPE>
114/// static void copyConstruct(TARGET_TYPE *address,
115/// const TARGET_TYPE& original,
116/// bslma::Allocator *allocator);
117/// };
118/// @endcode
119/// Next, we implement three overloads of `Imp::copyConstruct`, each taking a
120/// different trait specialization. A fourth overload takes `false_type`
121/// instead of a trait specialization, for those types that don't match any
122/// traits. For testing purposes, in addition to copying the data member, each
123/// overload also increments a separate counter. These implementations are
124/// slightly simplified for readability:
125/// @code
126/// struct Imp {
127///
128/// // Counters for counting overload calls
129/// static int s_noTraitsCounter;
130/// static int s_usesBslmaAllocatorCounter;
131/// static int s_isPairCounter;
132/// static int s_isBitwiseCopyableCounter;
133///
134/// static void clearCounters() {
135/// s_noTraitsCounter = 0;
136/// s_usesBslmaAllocatorCounter = 0;
137/// s_isPairCounter = 0;
138/// s_isBitwiseCopyableCounter = 0;
139/// }
140///
141/// template <class TARGET_TYPE>
142/// static void
143/// copyConstruct(TARGET_TYPE *address,
144/// const TARGET_TYPE& original,
145/// bslma::Allocator *allocator,
146/// bslmf::SelectTraitCase<UsesBslmaAllocator>)
147/// {
148/// new (address) TARGET_TYPE(original, allocator);
149/// ++s_usesBslmaAllocatorCounter;
150/// }
151///
152/// template <class TARGET_TYPE>
153/// static void
154/// copyConstruct(TARGET_TYPE *address,
155/// const TARGET_TYPE& original,
156/// bslma::Allocator *allocator,
157/// bslmf::SelectTraitCase<IsPair>)
158/// {
159/// ScalarPrimitives::copyConstruct(&address->first, original.first,
160/// allocator);
161/// ScalarPrimitives::copyConstruct(&address->second, original.second,
162/// allocator);
163/// ++s_isPairCounter;
164/// }
165///
166/// template <class TARGET_TYPE>
167/// static void
168/// copyConstruct(TARGET_TYPE *address,
169/// const TARGET_TYPE& original,
170/// bslma::Allocator *,
171/// bslmf::SelectTraitCase<IsBitwiseCopyable>)
172/// {
173/// memcpy(address, &original, sizeof(original));
174/// ++s_isBitwiseCopyableCounter;
175/// }
176///
177/// template <class TARGET_TYPE>
178/// static void
179/// copyConstruct(TARGET_TYPE *address,
180/// const TARGET_TYPE& original,
181/// bslma::Allocator *,
182/// bslmf::SelectTraitCase<>)
183/// {
184/// new (address) TARGET_TYPE(original);
185/// ++s_noTraitsCounter;
186/// }
187/// };
188///
189/// int Imp::s_noTraitsCounter = 0;
190/// int Imp::s_usesBslmaAllocatorCounter = 0;
191/// int Imp::s_isPairCounter = 0;
192/// int Imp::s_isBitwiseCopyableCounter = 0;
193/// @endcode
194/// Then, we implement `ScalarPrimitives::copyConstruct`:
195/// @code
196/// template <class TARGET_TYPE>
197/// inline void
198/// ScalarPrimitives::copyConstruct(TARGET_TYPE *address,
199/// const TARGET_TYPE& original,
200/// bslma::Allocator *allocator)
201/// {
202/// @endcode
203/// We use `bslmf::SelectTrait` to declare `Selection` as a specialization
204/// of the first match of the specified traits:
205/// @code
206/// typedef typename bslmf::SelectTrait<TARGET_TYPE,
207/// UsesBslmaAllocator,
208/// IsBitwiseCopyable,
209/// IsPair>::Type Selection;
210/// @endcode
211/// Now, we use `Selection` to choose (at compile time), one of the
212/// `Imp::copyConstruct` overloads defined above:
213/// @code
214/// Imp::copyConstruct(address, original, allocator, Selection());
215/// } // end copyConstruct()
216///
217/// } // Close namespace bslalg
218/// @endcode
219/// Finally, we define three classes, associated with each of the three traits
220/// of interest, a fourth class associated with more than one trait (to show
221/// that the selection mechanism respects preference) and a fifth class that is
222/// not associated with any trait.
223///
224/// The first class is associated with the `UsesBslmaAllocator` trait:
225/// @code
226/// class TypeWithAllocator {
227/// int d_value;
228/// bslma::Allocator *d_alloc;
229/// public:
230/// TypeWithAllocator(int v = 0, bslma::Allocator *a = 0) // IMPLICIT
231/// : d_value(v), d_alloc(a) { }
232/// TypeWithAllocator(const TypeWithAllocator& other,
233/// bslma::Allocator *a = 0)
234/// : d_value(other.d_value), d_alloc(a) { }
235///
236/// int value() const { return d_value; }
237/// bslma::Allocator *allocator() const { return d_alloc; }
238/// };
239///
240/// template <> struct UsesBslmaAllocator<TypeWithAllocator>
241/// : bsl::true_type { };
242/// @endcode
243/// The second class is associated with the `IsBitwiseCopyable` trait:
244/// @code
245/// class BitwiseCopyableType {
246/// int d_value;
247/// public:
248/// BitwiseCopyableType(int v = 0) : d_value(v) { } // IMPLICIT
249/// int value() const { return d_value; }
250/// };
251///
252/// template <> struct IsBitwiseCopyable<BitwiseCopyableType>
253/// : bsl::true_type { };
254/// @endcode
255/// The third class is associated with the `IsPair` trait:
256/// @code
257/// struct PairType {
258/// TypeWithAllocator first;
259/// BitwiseCopyableType second;
260///
261/// PairType(int a, int b) : first(a), second(b) { }
262/// };
263///
264/// template <> struct IsPair<PairType> : bsl::true_type { };
265/// @endcode
266/// The fourth class is associated with both the `IsPair` and
267/// `IsBitwiseCopyable` traits:
268/// @code
269/// struct BitwiseCopyablePairType {
270/// BitwiseCopyableType first;
271/// BitwiseCopyableType second;
272///
273/// BitwiseCopyablePairType(int a, int b) : first(a), second(b) { }
274/// };
275///
276/// template <> struct IsPair<BitwiseCopyablePairType> : bsl::true_type { };
277/// template <> struct IsBitwiseCopyable<BitwiseCopyablePairType>
278/// : bsl::true_type { };
279/// @endcode
280/// The fifth class is not associated with any explicit traits:
281/// @code
282/// class TypeWithNoTraits {
283/// int d_value;
284/// public:
285/// TypeWithNoTraits(int v = 0) : d_value(v) { } // IMPLICIT
286/// int value() const { return d_value; }
287/// };
288/// @endcode
289/// We use these classes to instantiate `ScalarPrimitives::copyConstruct` and
290/// verify that the most efficient copy operation that is valid for each type
291/// is applied:
292/// @code
293/// int usageExample1()
294/// {
295/// using bslalg::Imp;
296///
297/// // This buffer is properly aligned and big enough to hold any of the
298/// // test types.
299/// void *buffer[4];
300/// char dummy[2]; // Dummy addresses
301///
302/// bslma::Allocator *a1 = (bslma::Allocator*) &dummy[0];
303/// bslma::Allocator *a2 = (bslma::Allocator*) &dummy[1];
304/// @endcode
305/// When we call `ScalarPrimitives::copyConstruct` for an object of
306/// `TypeWithAllocator`, we expect that the copy will have the same value but a
307/// different allocator than the original and that the
308/// `UsesBslmaAllocator` copy implementation will be called once:
309/// @code
310/// Imp::clearCounters();
311/// TypeWithAllocator twa(1, a1);
312/// TypeWithAllocator *twaptr = (TypeWithAllocator*) buffer;
313/// bslalg::ScalarPrimitives::copyConstruct(twaptr, twa, a2);
314/// assert(1 == Imp::s_usesBslmaAllocatorCounter);
315/// assert(1 == twaptr->value());
316/// assert(a2 == twaptr->allocator());
317/// twaptr->~TypeWithAllocator();
318/// @endcode
319/// When we call `ScalarPrimitives::copyConstruct` for an object of
320/// `BitwiseCopyableType`, we expect that the `IsBitwiseCopyable` copy
321/// implementation will be called once:
322/// @code
323/// Imp::clearCounters();
324/// BitwiseCopyableType bct(2);
325/// BitwiseCopyableType *bctptr = (BitwiseCopyableType*) buffer;
326/// bslalg::ScalarPrimitives::copyConstruct(bctptr, bct, a2);
327/// assert(1 == Imp::s_isBitwiseCopyableCounter);
328/// assert(2 == bctptr->value());
329/// bctptr->~BitwiseCopyableType();
330/// @endcode
331/// When we call `ScalarPrimitives::copyConstruct` for an object of
332/// `PairType`, we expect that the `IsPair` copy implementation will be
333/// called once for the pair as whole and that the
334/// `UsesBslmaAllocator` and `IsBitwiseCopyable` implementations
335/// will be called for the `first` and `second` members, respectively:
336/// @code
337/// Imp::clearCounters();
338/// PairType pt(3, 4);
339/// PairType *ptptr = (PairType*) buffer;
340/// bslalg::ScalarPrimitives::copyConstruct(ptptr, pt, a2);
341/// assert(1 == Imp::s_isPairCounter);
342/// assert(1 == Imp::s_usesBslmaAllocatorCounter);
343/// assert(1 == Imp::s_usesBslmaAllocatorCounter);
344/// assert(3 == ptptr->first.value());
345/// assert(a2 == ptptr->first.allocator());
346/// assert(4 == ptptr->second.value());
347/// ptptr->~PairType();
348/// @endcode
349/// When we call `ScalarPrimitives::copyConstruct` for an object of
350/// `BitwiseCopyablePairType`, the `IsBitwiseCopyable` trait takes precedence
351/// over the `IsPair` trait (because it appears first in the list of traits
352/// used to instantiate `SelectTrait`). Therefore, we expect to see the
353/// `IsBitwiseCopyable` copy implementation called once for the whole
354/// pair and the `IsPair` copy implementation not called at all:
355/// @code
356/// Imp::clearCounters();
357/// BitwiseCopyablePairType bcpt(5, 6);
358/// BitwiseCopyablePairType *bcptbcptr = (BitwiseCopyablePairType*) buffer;
359/// bslalg::ScalarPrimitives::copyConstruct(bcptbcptr, bcpt, a2);
360/// // Prefer IsBitwiseCopyable over IsPair trait
361/// assert(1 == Imp::s_isBitwiseCopyableCounter);
362/// assert(0 == Imp::s_isPairCounter);
363/// assert(5 == bcptbcptr->first.value());
364/// assert(6 == bcptbcptr->second.value());
365/// bcptbcptr->~BitwiseCopyablePairType();
366/// @endcode
367/// When we call `ScalarPrimitives::copyConstruct` for an object of
368/// `TypeWithNoTraits`, we expect none of the specialized copy implementations
369/// to be called, thus defaulting to the `false_type` copy implementation:
370/// @code
371/// Imp::clearCounters();
372/// TypeWithNoTraits twnt(7);
373/// TypeWithNoTraits *twntptr = (TypeWithNoTraits*) buffer;
374/// bslalg::ScalarPrimitives::copyConstruct(twntptr, twnt, a2);
375/// assert(1 == Imp::s_noTraitsCounter);
376/// assert(7 == twntptr->value());
377/// twntptr->~TypeWithNoTraits();
378///
379/// return 0;
380/// }
381/// @endcode
382/// Note that using `SelectTraits` for dispatching using overloading imposes
383/// little or no overhead, since the compiler typically generates no code for
384/// the constructor or copy constructor of the trait argument to
385/// the overloaded functions. When inlining is in effect, the result is very
386/// efficient.
387/// @}
388/** @} */
389/** @} */
390
391/** @addtogroup bsl
392 * @{
393 */
394/** @addtogroup bslmf
395 * @{
396 */
397/** @addtogroup bslmf_selecttrait
398 * @{
399 */
400
401#include <bslscm_version.h>
402
404#include <bslmf_switch.h>
405
406
407
408namespace bslmf {
409
410 // ========================
411 // struct SelectTrait_False
412 // ========================
413
414/// Metafunction that always returns false.
415template <class>
419
420 // ======================
421 // struct SelectTraitCase
422 // ======================
423
424/// This template expresses a class that is unique for the specified
425/// (template parameter) `t_TRAIT` metafunction. An instantiation of this
426/// template is the "compile-time return value" of `SelectTrait` (see
427/// below). `SelectTraitCase` acts as a sort of compile-time
428/// pointer-to-metafunction that holds the identity of a metafunction
429/// similar to the way a pointer-to-function holds (at run-time) the
430/// identity of a function. As in the pointer-to-function case, a
431/// `SelectTraitCase` can also be used indirectly to evaluate `t_TRAIT` (at
432/// compile time). Also note that, when `SelectTraitCase` is specialized
433/// with the default `t_TRAIT` type parameter, `SelectTrait_False`, it
434/// essentially means that none of the traits specified to `SelectTrait`
435/// match.
436template <template <class> class t_TRAIT = SelectTrait_False>
438{
439
440 /// Evaluates `t_TRAIT` for the specified (template parameter) `T` type.
441 /// The resulting `Eval<T>` instantiation is derived from `true_type` if
442 /// `t_TRAIT<T>` is derived from `true_type` and `false_type` if
443 /// `t_TRAIT<T>` is derived from `false_type`. (More generally,
444 /// `Eval<T>` is derived from `t_TRAIT<T>::type`.)
445 template <class t_TYPE>
446 struct Eval : public t_TRAIT<t_TYPE>::type {
447 };
448
450};
451
452 // ======================
453 // struct SelectTrait_Imp
454 // ======================
455
456template <class t_TYPE,
457 template <class> class t_TRAIT1,
458 template <class> class t_TRAIT2,
459 template <class> class t_TRAIT3,
460 template <class> class t_TRAIT4,
461 template <class> class t_TRAIT5,
462 template <class> class t_TRAIT6,
463 template <class> class t_TRAIT7,
464 template <class> class t_TRAIT8,
465 template <class> class t_TRAIT9>
467 enum {
468 ORDINAL = (t_TRAIT1<t_TYPE>::value ? 1
469 : t_TRAIT2<t_TYPE>::value ? 2
470 : t_TRAIT3<t_TYPE>::value ? 3
471 : t_TRAIT4<t_TYPE>::value ? 4
472 : t_TRAIT5<t_TYPE>::value ? 5
473 : t_TRAIT6<t_TYPE>::value ? 6
474 : t_TRAIT7<t_TYPE>::value ? 7
475 : t_TRAIT8<t_TYPE>::value ? 8
476 : t_TRAIT9<t_TYPE>::value ? 9
477 : 0)
478 };
479
480 typedef typename Switch<ORDINAL,
491};
492
493 // ==================
494 // struct SelectTrait
495 // ==================
496
497/// Instantiate each specified (template parameter) `t_TRAIT1` to `t_TRAIT9`
498/// metafunction using the specified (template parameter) `t_TYPE`. Inherit
499/// from `SelectTraitCase<TRAITx>`, where *x* is `1` if
500/// `t_TRAIT1<t_TYPE>::value` is true, `2` if `t_TRAIT2<t_TYPE>::value` is
501/// true, etc.. If none of the traits evaluates to true, then inherit from
502/// `SelectTraitCase<>`, which means that none of the traits match.
503template <class t_TYPE,
504 template <class> class t_TRAIT1,
505 template <class> class t_TRAIT2 = SelectTrait_False,
506 template <class> class t_TRAIT3 = SelectTrait_False,
507 template <class> class t_TRAIT4 = SelectTrait_False,
508 template <class> class t_TRAIT5 = SelectTrait_False,
509 template <class> class t_TRAIT6 = SelectTrait_False,
510 template <class> class t_TRAIT7 = SelectTrait_False,
511 template <class> class t_TRAIT8 = SelectTrait_False,
512 template <class> class t_TRAIT9 = SelectTrait_False>
514 t_TRAIT1,
515 t_TRAIT2,
516 t_TRAIT3,
517 t_TRAIT4,
518 t_TRAIT5,
519 t_TRAIT6,
520 t_TRAIT7,
521 t_TRAIT8,
522 t_TRAIT9>::Type {
523
524 public:
525 enum {
526 ORDINAL = SelectTrait_Imp<t_TYPE,
527 t_TRAIT1,
528 t_TRAIT2,
529 t_TRAIT3,
530 t_TRAIT4,
531 t_TRAIT5,
532 t_TRAIT6,
533 t_TRAIT7,
534 t_TRAIT8,
535 t_TRAIT9>::ORDINAL
536 };
537
539};
540
541} // close package namespace
542
543
544
545#endif // ! defined(INCLUDED_BSLMF_SELECTTRAIT)
546
547// ----------------------------------------------------------------------------
548// Copyright 2013 Bloomberg Finance L.P.
549//
550// Licensed under the Apache License, Version 2.0 (the "License");
551// you may not use this file except in compliance with the License.
552// You may obtain a copy of the License at
553//
554// http://www.apache.org/licenses/LICENSE-2.0
555//
556// Unless required by applicable law or agreed to in writing, software
557// distributed under the License is distributed on an "AS IS" BASIS,
558// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
559// See the License for the specific language governing permissions and
560// limitations under the License.
561// ----------------------------- END-OF-FILE ----------------------------------
562
563/** @} */
564/** @} */
565/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlbb_blob.h:576
Definition bslmf_integralconstant.h:244
Definition bslmf_selecttrait.h:446
Definition bslmf_selecttrait.h:438
SelectTraitCase Type
Definition bslmf_selecttrait.h:449
Metafunction that always returns false.
Definition bslmf_selecttrait.h:417
Definition bslmf_selecttrait.h:466
@ ORDINAL
Definition bslmf_selecttrait.h:468
Switch< ORDINAL, SelectTraitCase<>, SelectTraitCase< t_TRAIT1 >, SelectTraitCase< t_TRAIT2 >, SelectTraitCase< t_TRAIT3 >, SelectTraitCase< t_TRAIT4 >, SelectTraitCase< t_TRAIT5 >, SelectTraitCase< t_TRAIT6 >, SelectTraitCase< t_TRAIT7 >, SelectTraitCase< t_TRAIT8 >, SelectTraitCase< t_TRAIT9 > >::Type Type
Definition bslmf_selecttrait.h:490
Definition bslmf_selecttrait.h:522
@ ORDINAL
Definition bslmf_selecttrait.h:526
bsl::integral_constant< int, ORDINAL > OrdinalType
Definition bslmf_selecttrait.h:538
Definition bslmf_switch.h:537