BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_isbitwiseequalitycomparable.h
Go to the documentation of this file.
1/// @file bslmf_isbitwiseequalitycomparable.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslmf_isbitwiseequalitycomparable.h -*-C++-*-
8#ifndef INCLUDED_BSLMF_ISBITWISEEQUALITYCOMPARABLE
9#define INCLUDED_BSLMF_ISBITWISEEQUALITYCOMPARABLE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslmf_isbitwiseequalitycomparable bslmf_isbitwiseequalitycomparable
15/// @brief Provide a type trait for bitwise equality.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslmf
19/// @{
20/// @addtogroup bslmf_isbitwiseequalitycomparable
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslmf_isbitwiseequalitycomparable-purpose"> Purpose</a>
25/// * <a href="#bslmf_isbitwiseequalitycomparable-classes"> Classes </a>
26/// * <a href="#bslmf_isbitwiseequalitycomparable-description"> Description </a>
27/// * <a href="#bslmf_isbitwiseequalitycomparable-usage"> Usage </a>
28/// * <a href="#bslmf_isbitwiseequalitycomparable-example-1-using-the-trait-to-optimize-range-comparison"> Example 1: Using the trait to optimize range comparison </a>
29/// * <a href="#bslmf_isbitwiseequalitycomparable-example-2-associating-a-trait-with-a-class-template"> Example 2: Associating a Trait with a Class Template </a>
30///
31/// # Purpose {#bslmf_isbitwiseequalitycomparable-purpose}
32/// Provide a type trait for bitwise equality.
33///
34/// # Classes {#bslmf_isbitwiseequalitycomparable-classes}
35///
36/// - bslmf::IsBitwiseEqualityComparable: trait metafunction
37///
38/// # Description {#bslmf_isbitwiseequalitycomparable-description}
39/// This component provides a single trait metafunction,
40/// `bslmf::IsBitwiseEqualityComparable`, which allows generic code to determine
41/// whether objects of the specified `t_TYPE` can be compared using `memcmp`.
42/// Such types are said to be bitwise EqualityComparable. Observe that this
43/// trait may be `true` only for object types, even though, for example,
44/// reference types may be guaranteed identical bit representations when they
45/// refer to the same object, just as the corresponding pointer type would be
46/// bitwise EqualityComparable.
47///
48/// For a type to be bitwise EqalityComparable, each bit of its object
49/// representation must be significant in the value representation, and distinct
50/// sequences of bits represent different values, i.e., this trait is an
51/// assertion that the specified `t_TYPE` has unique representations for each
52/// possible value, and no padding bits. This property is deemed to hold for
53/// `bool` and enumerations where, in practice, the compiler will enforce a
54/// value representation over all the seemingly unused bits. For a C++17 tool
55/// chain, this trait should be equivalent to the
56/// `std::has_unique_object_representation` trait.
57///
58/// Note that as arrays are not allowed to introduce padding, arrays of a
59/// bitwise EqualityComparable `t_TYPE` are also bitwise EqualityComparable,
60/// even though they do not provide an overloaded `operator==`. While
61/// transforming comparisons of a single object using this trait into calls to
62/// `memcmp` is unlikely to be profitable, transforming comparisons of a whole
63/// array into a single `memcmp` call is more likely to be beneficial.
64///
65/// ## Usage {#bslmf_isbitwiseequalitycomparable-usage}
66///
67///
68///
69/// ### Example 1: Using the trait to optimize range comparison {#bslmf_isbitwiseequalitycomparable-example-1-using-the-trait-to-optimize-range-comparison}
70///
71///
72/// Suppose we want to compare two sequences of the same object type to
73/// determine whether or not they hold the same values. The simplest solution
74/// would be to iterate over both sequences, comparing each member, and return
75/// `false` as soon as any pair of elements do not compare equal; if we walk all
76/// the way to the end of both sequences, then they hold the same values. If we
77/// want to perform this comparison most efficiently though, we would rather not
78/// invoke `operator==` on each member, and instead defer to the `memcmp`
79/// function in the standard library that is highly optimized (often to take
80/// advantage of platform-specific instructions) for comparing ranges of raw
81/// memory. We can switch to this other technique only if we know that the
82/// value representations of a type are unique, rely on all of the bits in their
83/// representation, and do not have strange values like `NaN` that self-compare
84/// as `false`. This property is denoted by the `IsBitwiseEqualityComparable`
85/// trait.
86///
87/// First, we create a simple `struct` that contains a `char` and a `short` as
88/// its two data members, and supported comparison with `operator==`. Note that
89/// there will be a byte of padding between the `char` and the `short` members
90/// to ensure proper alignment. We insert telemetry to count the number of
91/// times `operator==` is called:
92/// @code
93/// namespace BloombergLP {
94///
95/// struct SimpleType {
96/// // This 'struct' holds two data members with a byte of padding, and can
97/// // be compared using the overloaded 'operator=='.
98///
99/// char d_dataC;
100/// short d_dataS;
101///
102/// static int s_comparisons;
103///
104/// friend bool operator==(const SimpleType& a, const SimpleType& b)
105/// // Return 'true' if the specified 'a' has the same value as the
106/// // specified 'b'. Two 'SimpleType' objects have the same value if
107/// // their corresponding 'd_dataC' and 'd_dataS' members have the
108/// // same value. The static data member 's_comparisons' is
109/// // incremented by one each time this function is called.
110/// {
111/// ++s_comparisons;
112/// return a.d_dataC == b.d_dataC
113/// && a.d_dataS == b.d_dataS;
114/// }
115///
116/// friend bool operator!=(const SimpleType& a, const SimpleType& b)
117/// // Return 'true' if the specified 'a' does not have the same value
118/// // as the specified 'b'. Two 'SimpleType' objects do not have the
119/// // same value if their corresponding 'd_dataC' and 'd_dataS'
120/// // members do not have the same value. The static data member
121/// // 's_comparisons' is incremented by one each time this function is
122/// // called.
123/// {
124/// ++s_comparisons;
125/// return a.d_dataC != b.d_dataC
126/// || a.d_dataS != b.d_dataS;
127/// }
128/// };
129///
130/// int SimpleType::s_comparisons = 0;
131/// @endcode
132/// Then, we create another `struct` that wraps a single `int` as its only data
133/// member, and supports comparison with `operator==`, inserting telemetry to
134/// count the number of times `operator==` is called:
135/// @code
136/// struct SecondType {
137/// // This 'struct' holds a single 'int' member, 'd_data', and can be
138/// // compared using the overloaded 'operator=='.
139/// @endcode
140/// We associate the bitwise EqualityComparable trait with `SecondType` using
141/// the BDE nested trait declaration facility:
142/// @code
143/// BSLMF_NESTED_TRAIT_DECLARATION(SecondType,
144/// bslmf::IsBitwiseEqualityComparable);
145///
146/// int d_data;
147///
148/// static int s_comparisons;
149///
150/// friend bool operator==(const SecondType& a, const SecondType& b)
151/// // Return 'true' if the specified 'a' has the same value as the
152/// // specified 'b'. Two 'SecondType' objects have the same value if
153/// // their corresponding 'd_data' elements have the same value. The
154/// // static data member 's_comparisons' is incremented by one each
155/// // time this function is called.
156/// {
157/// ++s_comparisons;
158/// return a.d_data == b.d_data;
159/// }
160///
161/// friend bool operator!=(const SecondType& a, const SecondType& b)
162/// // Return 'true' if the specified 'a' does not have the same value
163/// // as the specified 'b'. Two 'SecondType' objects do not have the
164/// // same value if their corresponding 'd_data' elements do not have
165/// // the same value. The static data member 's_comparisons' is
166/// // incremented by one each time this function is called.
167/// {
168/// ++s_comparisons;
169/// return a.d_data != b.d_data;
170/// }
171/// };
172///
173/// int SecondType::s_comparisons = 0;
174/// @endcode
175/// Next, we create another `struct` that wraps a single `int` as its only data
176/// member, and supports comparison with `operator==`, inserting telemetry to
177/// count the number of times `operator==` is called:
178/// @code
179/// struct ThirdType {
180/// // This 'struct' holds a single 'int' member, 'd_data', and can be
181/// // compared using the overloaded 'operator=='.
182///
183/// int d_data;
184///
185/// static int s_comparisons;
186///
187/// friend bool operator==(const ThirdType& a, const ThirdType& b)
188/// // Return 'true' if the specified 'a' has the same value as the
189/// // specified 'b'. Two 'SecondType' objects have the same value if
190/// // their corresponding 'd_data' elements have the same value. The
191/// // static data member 's_comparisons' is incremented by one each
192/// // time this function is called.
193/// {
194/// ++s_comparisons;
195/// return a.d_data == b.d_data;
196/// }
197///
198/// friend bool operator!=(const ThirdType& a, const ThirdType& b)
199/// // Return 'true' if the specified 'a' does not have the same value
200/// // as the specified 'b'. Two 'ThirdType' objects do not have the
201/// // same value if their corresponding 'd_data' elements do not have
202/// // the same value. The static data member 's_comparisons' is
203/// // incremented by one each time this function is called.
204/// {
205/// ++s_comparisons;
206/// return a.d_data != b.d_data;
207/// }
208/// };
209///
210/// int ThirdType::s_comparisons = 0;
211/// @endcode
212/// We associate the bitwise EqualityComparable trait with `ThirdType` by
213/// explicitly specializing the trait:
214/// @code
215/// namespace bslmf {
216/// template <>
217/// struct IsBitwiseEqualityComparable<ThirdType> : bsl::true_type {};
218/// } // close namespace bslmf
219/// @endcode
220/// Now, we write a function template to compare two arrays of the same type:
221/// @code
222/// template <class t_TYPE>
223/// bool rangeCompare(const t_TYPE *start, size_t length, const t_TYPE *other)
224/// {
225/// @endcode
226/// If we detect the bitwise EqualityComparable trait, we rely on the optimized
227/// `memcmp` function:
228/// @code
229/// if (bslmf::IsBitwiseEqualityComparable<t_TYPE>::value) {
230/// return 0 == memcmp(start,
231/// other,
232/// length * sizeof(t_TYPE)); // RETURN
233/// }
234/// @endcode
235/// Otherwise we iterate over the range directly until we find a pair of
236/// elements that do not have the same value, and return `true` if we reach the
237/// end of the range.
238/// @code
239/// if (0 != length) {
240/// while (*start++ == *other++) {
241/// if (!--length) {
242/// return true; // RETURN
243/// }
244/// }
245/// }
246/// return false;
247/// }
248/// @endcode
249/// Finally, we write a test to confirm that two arrays containing different
250/// values do not compare as equal (using our array comparison function), and
251/// that an array compares equal to itself, as it does comprise elements all
252/// having the same value. By inspecting the static data members provided for
253/// telemetry, we can confirm that `operator==` is called only for `SimpleType`
254/// as the other two `struct`s dispatch to `memcmp` instead:
255/// @code
256/// int usageExample1()
257/// {
258/// @endcode
259/// We confirm the initial state of the telemetry:
260/// @code
261/// assert(0 == SimpleType::s_comparisons);
262/// assert(0 == SecondType::s_comparisons);
263/// assert(0 == ThirdType ::s_comparisons);
264/// @endcode
265/// Then we create zero-initialized arrays for each of the types to be tested,
266/// and a second array for each type with a set of values distinct from all
267/// zeroes:
268/// @code
269/// const SimpleType simpleZeroes[10] = { };
270/// const SecondType secondZeroes[10] = { };
271/// const ThirdType thirdZeroes [10] = { };
272///
273/// const SimpleType simpleValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
274/// const SecondType secondValues[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
275/// const ThirdType thirdValues [10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
276/// @endcode
277/// Next we confirm that the two arrays (of each type) do not compare equal, and
278/// inspect the telemetry to confirm that the comparison operator was called for
279/// only the `SimpleType` without the bitwise EqualityComparable trait:
280/// @code
281/// assert(!rangeCompare(simpleZeroes, 10u, simpleValues) );
282/// assert(!rangeCompare(secondZeroes, 10u, secondValues) );
283/// assert(!rangeCompare(thirdZeroes, 10u, thirdValues) );
284///
285/// assert(0 < SimpleType::s_comparisons);
286/// assert(0 == SecondType::s_comparisons);
287/// assert(0 == ThirdType ::s_comparisons);
288///
289/// @endcode
290/// Then we reset the telemetry and confirm that an array of each type compares
291/// equal to itself, and inspect the telemetry to confirm that the comparison
292/// operator was called for only the `SimpleType` without the bitwise
293/// EqualityComparable trait:
294/// @code
295/// SimpleType::s_comparisons = 0;
296///
297/// assert( rangeCompare(simpleValues, 10u, simpleValues) );
298/// assert( rangeCompare(secondValues, 10u, secondValues) );
299/// assert( rangeCompare(thirdZeroes, 10u, thirdZeroes) );
300///
301/// assert(0 < SimpleType::s_comparisons);
302/// assert(0 == SecondType::s_comparisons);
303/// assert(0 == ThirdType ::s_comparisons);
304///
305/// return 0;
306/// }
307///
308/// } // close enterprise namespace
309/// @endcode
310///
311/// ### Example 2: Associating a Trait with a Class Template {#bslmf_isbitwiseequalitycomparable-example-2-associating-a-trait-with-a-class-template}
312///
313///
314/// In this example, we associate a trait not with a class, but with a class
315/// *template*. We create a "control" template that is not bitwise
316/// EqualityComparable, and two class templates, each of which uses a different
317/// mechanisms for being associated with the `IsBitwiseEqualityComparable`
318/// trait. First, we define a class template that is not bitwise
319/// EqualityComparable, `NotComparable`:
320/// @code
321/// namespace BloombergLP {
322///
323/// template <class t_TYPE>
324/// struct NotComparable
325/// {
326/// t_TYPE d_value;
327/// };
328/// @endcode
329/// Then, we define the class template `PotentiallyComparable1`, which uses
330/// partial template specialization to associate the
331/// `IsBitwiseEqualityComparable` trait with each instantiation on a `t_TYPE`
332/// that is itself bitwise EqualityComparable:
333/// @code
334/// template <class t_TYPE>
335/// struct PotentiallyComparable1
336/// {
337/// t_TYPE d_value;
338/// };
339///
340/// namespace bslmf {
341/// template <class t_TYPE>
342/// struct IsBitwiseEqualityComparable<PotentiallyComparable1<t_TYPE> >
343/// : IsBitwiseEqualityComparable<t_TYPE>::type {
344/// };
345/// } // close namespace bslmf
346/// @endcode
347/// Next, we define the class template'PotentiallyComparable2', which uses the
348/// `BSLMF_NESTED_TRAIT_DECLARATION` macro to associate the
349/// `IsBitwiseEqualityComparable` trait with each instantiation on a `t_TYPE`
350/// that is itself bitwise EqualityComparable:
351/// @code
352/// template <class t_TYPE>
353/// struct PotentiallyComparable2
354/// {
355/// t_TYPE d_value;
356///
357/// BSLMF_NESTED_TRAIT_DECLARATION_IF(
358/// PotentiallyComparable2,
359/// bslmf::IsBitwiseEqualityComparable,
360/// bslmf::IsBitwiseEqualityComparable<t_TYPE>::value);
361/// };
362/// @endcode
363/// Finally, we check that the traits are correctly associated by instantiating
364/// each template with types that are bitwise EqualityComparable and with types
365/// that are not not bitwise EqualityComparable, verifying the value of
366/// `IsBitwiseEqualityComparable<T>::value` in each case:
367/// @code
368/// int usageExample2()
369/// {
370/// using namespace bslmf;
371///
372/// assert(!IsBitwiseEqualityComparable<NotComparable<int> >::value);
373/// assert(!IsBitwiseEqualityComparable<
374/// NotComparable<NotComparable<int> > >::value);
375///
376/// assert( IsBitwiseEqualityComparable<
377/// PotentiallyComparable1<int> >::value);
378/// assert(!IsBitwiseEqualityComparable<
379/// PotentiallyComparable1<NotComparable<int> > >::value);
380///
381/// assert( IsBitwiseEqualityComparable<
382/// PotentiallyComparable2<int> >::value);
383/// assert(!IsBitwiseEqualityComparable<
384/// PotentiallyComparable2<NotComparable<int> > >::value);
385///
386/// return 0;
387/// }
388///
389/// } // close enterprise namespace
390/// @endcode
391/// @}
392/** @} */
393/** @} */
394
395/** @addtogroup bsl
396 * @{
397 */
398/** @addtogroup bslmf
399 * @{
400 */
401/** @addtogroup bslmf_isbitwiseequalitycomparable
402 * @{
403 */
404
405#include <bslscm_version.h>
406
409#include <bslmf_isconst.h>
410#include <bslmf_voidtype.h>
411
412#include <bsls_platform.h>
413
414#include <stddef.h>
415
416#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
417#include <bslmf_isenum.h>
418#endif
419
420
421
422namespace bslmf {
423
424template <class t_TYPE>
425struct IsBitwiseEqualityComparable;
426
427#if defined(BSLS_PLATFORM_CMP_IBM)
428 // =========================================
429 // struct IsBitwiseEqualityComparable_Scalar
430 // =========================================
431
432template <class t_TYPE, class = void>
433struct IsBitwiseEqualityComparable_Imp2 : bsl::false_type {
434};
435template <class t_TYPE>
436struct IsBitwiseEqualityComparable_Imp2<t_TYPE, BSLMF_VOIDTYPE(t_TYPE[])>
438 // This implementation-detail trait determines whether 't_TYPE' is a scalar
439 // type (an arithmetic type, enumeration, pointer, or pointer-to-member).
440 // This implementation takes advantage of a previous layer of filtering
441 // handling all class-types, so any remaining types that are valid as array
442 // elements must be scalar types, i.e., the 'BSLMF_VOIDTYPE' test will
443 // filter function types and reference types.
444};
445
446 // ======================================
447 // struct IsBitwiseEqualityComparable_Imp
448 // ======================================
449
450template <class t_TYPE, class = void>
451struct IsBitwiseEqualityComparable_Imp
452: IsBitwiseEqualityComparable_Imp2<t_TYPE>::type {
453};
454template <class t_TYPE>
455struct IsBitwiseEqualityComparable_Imp<t_TYPE, BSLMF_VOIDTYPE(int t_TYPE::*)>
456: DetectNestedTrait<t_TYPE, IsBitwiseEqualityComparable>::type {
457 // This trait 'struct' derives from 'bsl::true_type' if (the template
458 // paramter) 't_TYPE' is a scalar type or a class with a nested trait
459 // declaration for the 'bslmf::IsBitwiseEqualityComparable' trait, and from
460 // 'bsl::false_type' otherwise. Note that this template handles only the
461 // class-type cases, delegating the final filtering for scalar types to a
462 // further trait template.
463};
464#else
465 // ======================================
466 // struct IsBitwiseEqualityComparable_Imp
467 // ======================================
468
469/// This trait `struct` derives from `bsl::true_type` if (the template
470/// paramter) `t_TYPE` is a scalar type or a class with a nested trait
471/// declaration for the `bslmf::IsBitwiseEqualityComparable` trait, and from
472/// `bsl::false_type` otherwise. Note that this implementation relies on
473/// the fact that reference and function types cannot be cv-qualified, and
474/// any other non-class type (that is not handled by specializations of the
475/// primary template) will be a scalar type.
476template <class t_TYPE, class = void>
477struct IsBitwiseEqualityComparable_Imp : bsl::is_const<const t_TYPE>::type {
478};
479template <class t_TYPE>
481: DetectNestedTrait<t_TYPE, IsBitwiseEqualityComparable>::type {
482};
483#endif
484
485 // ==================================
486 // struct IsBitwiseEqualityComparable
487 // ==================================
488
489/// This trait `struct` is a metafunction that determines whether the
490/// specified parameter `t_TYPE` is bitwise EqualityComparable. If
491/// `IsBitwiseEqualityComparable<t_TYPE>` is derived from `true_type` then
492/// `t_TYPE` is bitwise EqualityComparable. Otherwise, bitwise equality
493/// comparability cannot be inferred for `t_TYPE`. This trait can be
494/// associated with a bitwise EqualityComparable user-defined class by
495/// specializing this class or by using the `BSLMF_NESTED_TRAIT_DECLARATION`
496/// macro.
497template <class t_TYPE>
501
502template <class t_TYPE>
503struct IsBitwiseEqualityComparable<const t_TYPE>
504: IsBitwiseEqualityComparable<t_TYPE>::type {
505};
506template <class t_TYPE>
507struct IsBitwiseEqualityComparable<volatile t_TYPE>
508: IsBitwiseEqualityComparable<t_TYPE>::type {
509};
510template <class t_TYPE>
511struct IsBitwiseEqualityComparable<const volatile t_TYPE>
512: IsBitwiseEqualityComparable<t_TYPE>::type {
513};
514 // Partial specializations for cv-qualified types channel to a single
515 // instantiation of the implementation type. Note that we cannot derive
516 // through the 'Imp' type directly as we would not correctly handle
517 // cv-qualified types that have been explicitly specialized by our users.
518
519template <class t_TYPE, size_t t_LEN>
520struct IsBitwiseEqualityComparable<t_TYPE[t_LEN]>
521: IsBitwiseEqualityComparable<t_TYPE>::type {
522};
523template <class t_TYPE, size_t t_LEN>
524struct IsBitwiseEqualityComparable<const t_TYPE[t_LEN]>
525: IsBitwiseEqualityComparable<t_TYPE>::type {
526};
527template <class t_TYPE, size_t t_LEN>
528struct IsBitwiseEqualityComparable<volatile t_TYPE[t_LEN]>
529: IsBitwiseEqualityComparable<t_TYPE>::type {
530};
531template <class t_TYPE, size_t t_LEN>
532struct IsBitwiseEqualityComparable<const volatile t_TYPE[t_LEN]>
533: IsBitwiseEqualityComparable<t_TYPE>::type {
534};
535
536template <class t_TYPE>
538: IsBitwiseEqualityComparable<t_TYPE>::type {
539};
540template <class t_TYPE>
541struct IsBitwiseEqualityComparable<const t_TYPE[]>
542: IsBitwiseEqualityComparable<t_TYPE>::type {
543};
544template <class t_TYPE>
545struct IsBitwiseEqualityComparable<volatile t_TYPE[]>
546: IsBitwiseEqualityComparable<t_TYPE>::type {
547};
548template <class t_TYPE>
549struct IsBitwiseEqualityComparable<const volatile t_TYPE[]>
550: IsBitwiseEqualityComparable<t_TYPE>::type {
551};
552 // Partial specializations for array types, as arrays have a contiguity
553 // guarantee (that can inferred from pointer arithmetic rules) so this if a
554 // type is bitwise equality comparable, we can be sure there is no padding
555 // introduced by an array, so arrays of this type should have the same
556 // property.
557
558/// Explicit specialization to confirm that `void` types are never bitwise
559/// EqualityComparable. Note that cv-`void` types are covered by the
560/// partial specialization for any cv-qualified type.
561template <>
563
564/// Revert of {DRQS 143286899}. Once clients are fixed, change to false.
565/// Explicit specialization to confirm that floating point types are not
566/// bitwise EqualityComparable, as they typically have specific problematic
567/// values: NaNs do not compare equal with themselves, and there may be
568/// multiple representations for zero (with negative zero).
569template <>
571template <>
573template <>
575
576} // close package namespace
577
578
579#endif // ! defined(INCLUDED_BSLMF_ISBITWISEEQUALITYCOMPARABLE)
580
581// ----------------------------------------------------------------------------
582// Copyright 2019 Bloomberg Finance L.P.
583//
584// Licensed under the Apache License, Version 2.0 (the "License");
585// you may not use this file except in compliance with the License.
586// You may obtain a copy of the License at
587//
588// http://www.apache.org/licenses/LICENSE-2.0
589//
590// Unless required by applicable law or agreed to in writing, software
591// distributed under the License is distributed on an "AS IS" BASIS,
592// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
593// See the License for the specific language governing permissions and
594// limitations under the License.
595// ----------------------------- END-OF-FILE ----------------------------------
596
597/** @} */
598/** @} */
599/** @} */
#define BSLMF_VOIDTYPE(ARG)
Definition bslmf_voidtype.h:335
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlbb_blob.h:576
Definition bslmf_integralconstant.h:244
Definition bslmf_isconst.h:144
Definition bslmf_detectnestedtrait.h:464
Definition bslmf_isbitwiseequalitycomparable.h:477
Definition bslmf_isbitwiseequalitycomparable.h:499