BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslalg_typetraits

Macros

#define BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT)
 
#define BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)
 Like BSLALG_DECLARE_NESTED_TRAITS, but for two traits.
 
#define BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)
 Like BSLALG_DECLARE_NESTED_TRAITS, but for three traits.
 
#define BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)
 Like BSLALG_DECLARE_NESTED_TRAITS, but for four traits.
 
#define BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4, TRAIT5)
 Like BSLALG_DECLARE_NESTED_TRAITS, but for five traits.
 
#define BDEALG_DECLARE_NESTED_TRAITS(T, TRAITS)    BSLALG_DECLARE_NESTED_TRAITS(T, TRAITS)
 This alias is defined for backward compatibility.
 
#define BDEALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)    BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)
 This alias is defined for backward compatibility.
 
#define BDEALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)    BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)
 This alias is defined for backward compatibility.
 
#define BDEALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)    BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)
 This alias is defined for backward compatibility.
 
#define BDEALG_DECLARE_NESTED_TRAITS5(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4, TRAIT5)    BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5)
 This alias is defined for backward compatibility.
 
#define bdealg_HasTrait   bslalg::HasTrait
 This alias is defined for backward compatibility.
 
#define bdealg_SelectTrait   bslalg::SelectTrait
 This alias is defined for backward compatibility.
 

Detailed Description

Outline

Purpose

Provide compile-time traits that can be associated with types.

Deprecated:
Use bslmf_nestedtraitdeclaration instead.

Classes

Macros

See also
bslalg_constructorproxy, bslalg_scalarprimitives

Description

This component provides a set of type traits, and a set of macros used to assign traits to user-defined classes. Traits are used to enable certain optimizations or discriminations at compile-time. For instance, a class having the trait bslalg::TypeTraitBitwiseMoveable may allow resizing an array of objects by simply calling std::memcpy instead of invoking a copy-constructor on every object. The usage example shows how to use the bslalg::TypeTraitUsesBslmaAllocator to propagate allocators to nested objects that may require them.

This component should be used in conjunction with other components from the package bslalg. See the package-level documentation for an overview. The most useful classes and macros defined in this component are:

Entity Description
------ -----------
bslalg::TypeTraitBitwiseMoveable (See the corresponding class-level
BSLALG_DECLARE_NESTED_TRAITS(TYPE, TRAIT) A macro to attach a given 'TRAIT'
to a given type 'T' in a nested
fashion. This macro must be used
within the 'public' section of a
class body.
bslalg::HasTrait<TYPE, TRAIT> This meta-function computes
whether the parameterized 'TYPE'
possesses the parameterized
'TRAIT'.
bslalg::SelectTrait<T, TRAIT1, ...> This meta-function selects the
first trait possessed by the
parameterized 'TYPE' from the
ordered list 'TRAIT1', ....
#define BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT)
Definition bslalg_typetraits.h:422
Definition bdlc_flathashmap.h:1805
Definition bslalg_selecttrait.h:90
Definition bslalg_typetraitbitwisecopyable.h:88
Definition bslalg_typetraitbitwiseequalitycomparable.h:86
Definition bslalg_typetraitbitwisemoveable.h:87
Definition bslalg_typetraithasstliterators.h:82
Definition bslalg_typetraithastrivialdefaultconstructor.h:84
Definition bslalg_typetraitpair.h:83
Definition bslalg_typetraitusesbslmaallocator.h:83

Usage

In this usage example, we show how to enable the bslma allocator model for generic containers, by implementing simplified versions of the bslalg_constructorproxy and bslalg_scalarprimitives components. The interested reader should refer to the documentation of those components.

A Generic Container

Suppose we want to implement a generic container of a parameterized TYPE, which may or may not follow the bslma allocator model. If it does, our container should pass an extra bslma::Allocator* argument to copy construct a value; but if it does not, then passing this extra argument is going to generate a compile-time error. It thus appears we need two implementations of our container. This can be done more succinctly by encapsulating into the constructor some utilities that will, through a single interface, determine whether TYPE has the trait bslalg::TypeTraitUsesBslmaAllocator and copy-construct it accordingly.

The container contains a single data member of the parameterized TYPE. Since we are going to initialize this data member manually, we do not want it to be automatically constructed by the compiler. For this reason, we encapsulate it in a bsls::ObjectBuffer.

// my_genericcontainer.hpp -*-C++-*-
/// This generic container type contains a single object, always
/// initialized, which can be replaced and accessed. This container
/// always takes an allocator argument and thus follows the
/// `bslalg::TypeTraitUsesBslmaAllocator` protocol.
template <class TYPE>
class MyGenericContainer {
// PRIVATE DATA MEMBERS
Definition bsls_objectbuffer.h:276

Since the container offers a uniform interface that always takes an extra allocator argument, regardless of whether TYPE does or not, we can declare it to have the bslalg::TypeTraitUsesBslmaAllocator trait:

public:
// TRAITS
BSLALG_DECLARE_NESTED_TRAITS(MyGenericContainer,

For simplicity, we let the container contain only a single element, and require that an element always be initialized.

// CREATORS
/// Create a container containing the specified `object`, using the
/// optionally specified `allocator` to supply memory. If `allocator`
/// is 0, the currently installed allocator is used.
explicit MyGenericContainer(const TYPE& object,
bslma::Allocator *allocator = 0);
/// Create a container containing the same object as the specified
/// `container`, using the optionally specified `allocator` to supply
/// memory. If `allocator` is 0, the currently installed allocator is
/// used.
MyGenericContainer(const MyGenericContainer& container,
bslma::Allocator *allocator = 0);
/// Destroy this object.
~MyGenericContainer();
Definition bslma_allocator.h:457

We can also allow the container to change the object it contains, by granting modifiable as well as non-modifiable access to this object:

// MANIPULATORS
TYPE& object();
// ACCESSORS
const TYPE& object() const;
};

Using the Type Traits

The challenge in the implementation lies in using the traits of the contained TYPE to determine whether to pass the allocator argument to its copy constructor. We rely here on a property of templates that templates are not compiled (and thus will not generate compilation errors) until they are instantiated. Hence, we can use two function templates, and let the overloading resolution (based on the nested traits) decide which to instantiate. The generic way to create an object, passing through all arguments (value and allocator) is as follows. For brevity and to avoid breaking the flow of this example, we have embedded the function definition into the class.

// my_genericcontainer.cpp i -*-C++-*-
/// This `struct` provides a namespace for utilities implementing the
/// allocator pass-through mechanism in a generic container.
struct my_GenericContainerUtil {
/// Create a copy of the specified `value` at the specified
/// `location`, using the specified `allocator` to supply memory.
template <class TYPE>
static void copyConstruct(TYPE *location,
const TYPE& value,
bslma::Allocator *allocator,
{
new (location) TYPE(value, allocator);
}

For types that don't use an allocator, we offer the following overload that will be selected if the type trait of TYPE cannot be converted to bslalg::TypeTraitUsesBslmaAllocator. In that case, note that the type traits always inherit from bslalg::TypeTraitNil.

/// Create a copy of the specified `value` at the specified
/// `location`. Note that the specified `allocator` is ignored.
template <class TYPE>
static void copyConstruct(TYPE *location,
const TYPE& value,
bslma::Allocator *allocator,
{
new (location) TYPE(value);
}
Nil trait – every type has this trait.
Definition bslalg_typetraitnil.h:80

And finally, this function will instantiate the type trait and pass it to the appropriately (compiler-)chosen overload:

/// Create a copy of the specified `value` at the specified
/// `location`, optionally using the specified `allocator` to supply
/// memory if the parameterized `TYPE` possesses the
/// `bslalg::TypeTraitUsesBslmaAllocator`.
template <class TYPE>
static void copyConstruct(TYPE *location,
const TYPE& value,
bslma::Allocator *allocator)
{
copyConstruct(
location, value, allocator,
typename bsl::conditional<
HasTrait<TYPE,
}
};
Definition bslmf_conditional.h:120

Generic Container Implementation

With these utilities, we can now implement MyGenericContainer.

// CREATORS
template <typename TYPE>
MyGenericContainer<TYPE>::MyGenericContainer(const TYPE& object,
bslma::Allocator *allocator)
{
my_GenericContainerUtil::copyConstruct(&d_object.object(),
object,
allocator);
}
template <typename TYPE>
MyGenericContainer<TYPE>::MyGenericContainer(
const MyGenericContainer& container,
bslma::Allocator *allocator)
{
my_GenericContainerUtil::copyConstruct(&d_object.object(),
container.object(),
allocator);
}

Note that all this machinery only affects the constructors, and not the destructor which only invokes the destructor of d_object.

template <typename TYPE>
MyGenericContainer<TYPE>::~MyGenericContainer()
{
(&d_object.object())->~TYPE();
}

To finish, the accessors and manipulators are trivially implemented.

// MANIPULATORS
template <typename TYPE>
TYPE& MyGenericContainer<TYPE>::object()
{
return d_object.object();
}
// ACCESSORS
template <typename TYPE>
const TYPE& MyGenericContainer<TYPE>::object() const
{
return d_object.object();
}

Usage Verification

We can check that our container actually forwards the correct allocator to its contained objects with a very simple test apparatus, consisting of two classes that have exactly the same signature and implementation except that one has the bslalg::TypeTraitUsesBslmaAllocator trait and the other does not:

bslma::Allocator *allocSlot;
/// Class with declared traits. Calling copy constructor without an
/// allocator will compile, but will not set `allocSlot`.
struct MyTestTypeWithBslmaAllocatorTraits {
// TRAITS
BSLALG_DECLARE_NESTED_TRAITS(MyTestTypeWithBslmaAllocatorTraits,
BloombergLP::bslalg::TypeTraitUsesBslmaAllocator);
// CREATORS
MyTestTypeWithBslmaAllocatorTraits() {}
MyTestTypeWithBslmaAllocatorTraits(
const MyTestTypeWithBslmaAllocatorTraits&,
bslma::Allocator *allocator)
{
allocSlot = allocator;
}
};
/// Class with no declared traits. Calling copy constructor without
/// an allocator will not set the `allocSlot`, but passing it by mistake
/// will set it.
struct MyTestTypeWithNoBslmaAllocatorTraits {
// CREATORS
MyTestTypeWithNoBslmaAllocatorTraits() {}
MyTestTypeWithNoBslmaAllocatorTraits(
const MyTestTypeWithNoBslmaAllocatorTraits &,
bslma::Allocator *allocator)
{
allocSlot = allocator;
}
};

Our verification program simply instantiates several MyGenericContainer templates with the two test types above, and checks that the allocator slot is as expected:

int main()
{
Definition bslma_testallocator.h:384

With MyTestTypeWithNoBslmaAllocatorTraits, the slot should never be set.

MyTestTypeWithNoBslmaAllocatorTraits x;
allocSlot = &ta0;
MyGenericContainer<MyTestTypeWithNoBslmaAllocatorTraits> x0(x);
assert(&ta0 == allocSlot);
allocSlot = &ta0;
MyGenericContainer<MyTestTypeWithNoBslmaAllocatorTraits> x1(x, &ta1);
assert(&ta0 == allocSlot);

With MyTestTypeWithBslmaAllocatorTraits, the slot should be set to the allocator argument, or to 0 if not specified:

MyTestTypeWithBslmaAllocatorTraits y;
allocSlot = &ta0;
MyGenericContainer<MyTestTypeWithBslmaAllocatorTraits> y0(y);
assert(0 == allocSlot);
allocSlot = &ta0;
MyGenericContainer<MyTestTypeWithBslmaAllocatorTraits> y1(y, &ta1);
assert(&ta1 == allocSlot);
return 0;
}

Macro Definition Documentation

◆ BDEALG_DECLARE_NESTED_TRAITS

#define BDEALG_DECLARE_NESTED_TRAITS (   T,
  TRAITS 
)     BSLALG_DECLARE_NESTED_TRAITS(T, TRAITS)

◆ BDEALG_DECLARE_NESTED_TRAITS2

#define BDEALG_DECLARE_NESTED_TRAITS2 (   T,
  TRAIT1,
  TRAIT2 
)     BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)

◆ BDEALG_DECLARE_NESTED_TRAITS3

#define BDEALG_DECLARE_NESTED_TRAITS3 (   T,
  TRAIT1,
  TRAIT2,
  TRAIT3 
)     BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)

◆ BDEALG_DECLARE_NESTED_TRAITS4

#define BDEALG_DECLARE_NESTED_TRAITS4 (   T,
  TRAIT1,
  TRAIT2,
  TRAIT3,
  TRAIT4 
)     BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)

◆ BDEALG_DECLARE_NESTED_TRAITS5

#define BDEALG_DECLARE_NESTED_TRAITS5 (   T,
  TRAIT1,
  TRAIT2,
  TRAIT3,
  TRAIT4,
  TRAIT5 
)     BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5)

◆ bdealg_HasTrait

#define bdealg_HasTrait   bslalg::HasTrait

◆ bdealg_SelectTrait

#define bdealg_SelectTrait   bslalg::SelectTrait

◆ BSLALG_DECLARE_NESTED_TRAITS

#define BSLALG_DECLARE_NESTED_TRAITS (   T,
  TRAIT 
)
Value:
operator TRAIT::NestedTraitDeclaration<T>() const { \
return TRAIT::NestedTraitDeclaration<T>(); \
}

Associate the specified TRAIT tag with the specified T class. This macro must be invoked only within the public part of the definition of class T. TRAIT must name a class such that TRAIT::NestedTraitDeclaration<T> designates a class derived from bslmf::DetectNestedTrait.

◆ BSLALG_DECLARE_NESTED_TRAITS2

#define BSLALG_DECLARE_NESTED_TRAITS2 (   T,
  TRAIT1,
  TRAIT2 
)
Value:
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2)

◆ BSLALG_DECLARE_NESTED_TRAITS3

#define BSLALG_DECLARE_NESTED_TRAITS3 (   T,
  TRAIT1,
  TRAIT2,
  TRAIT3 
)
Value:
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2); \
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3)

◆ BSLALG_DECLARE_NESTED_TRAITS4

#define BSLALG_DECLARE_NESTED_TRAITS4 (   T,
  TRAIT1,
  TRAIT2,
  TRAIT3,
  TRAIT4 
)
Value:
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2); \
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3); \
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT4)

◆ BSLALG_DECLARE_NESTED_TRAITS5

#define BSLALG_DECLARE_NESTED_TRAITS5 (   T,
  TRAIT1,
  TRAIT2,
  TRAIT3,
  TRAIT4,
  TRAIT5 
)
Value:
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2); \
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3); \
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT4); \
BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT5)