Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmf_nestedtraitdeclaration
[Package bslmf]

Provide a nested declaration to associate a class with a trait. More...

Namespaces

namespace  bslmf

Detailed Description

Outline
Purpose:
Provide a nested declaration to associate a class with a trait.
Macros:
BSLMF_NESTED_TRAIT_DECLARATION macro that associates a trait with a class
BSLMF_NESTED_TRAIT_DECLARATION_IF conditional macro to associates a trait
See also:
Component bslmf_detectnestedtrait
Description:
This component defines a pair of macros, BSLMF_NESTED_TRAIT_DECLARATION and BSLMF_NESTED_TRAIT_DECLARATION_IF, that can be used in association with the facilities provided by bslmf_detectnestedtrait to declare that a given class has a given trait.
Traits provide a mechanism for convenient compile-time discovery of information about a class, which is useful in particular for providing efficient specializations of generalized containers and algorithms without having to rely on knowledge of specific target classes.
The primary public interface of this component consists of two macros that provide a facility for declaring that a given class has a given trait. These macros embed the association between the type and the trait inside the class definition itself, hence the term "nested trait declaration".
Note that the term "nested" is not meant to imply that this facility declares a nested type within the class namespace, only that the trait declaration appears as one of the public declarations that make up the class definition. For example, we could declare that a class, xyza::Foo, has the trait abcd::BarTrait in the following way:
  namespace xyza {

  class Foo {
      // ... various implementation details ...

    public:
      // TRAITS
      BSLMF_NESTED_TRAIT_DECLARATION(Foo, abcd::BarTrait);

      // ... the rest of the public interface ...
  };

  }  // close namespace xyza
Two flavors of macro are provided: one for declaring unconditionally that a class has a trait, and another for declaring that the class has a trait if and only if a given compile-time expression evaluates to true.
Relationship with "C++11-style" Type Traits:
Traits declared using this component are not automatically compatible mechanisms designed to detect "C++11-style" traits. For a full discussion of the relationship between nested traits and "C++11-style" traits, as well as best practices for defining, associating, and detecting traits, see the component documentation for bslmf_detectnestedtrait.
Usage:
This section illustrates the intended use of this component.
Example 1: Testing a Type for a Custom Trait:
When writing generic infrastructure code, we often need to choose among multiple code paths based on the capabilities of the types on which we are operating. If those capabilities are reflected in a type's public interface, we may be able to use techniques such as SFINAE to choose the appropriate code path. However, SFINAE cannot detect all of a type's capabilities. In particular, SFINAE cannot detect constructors, memory allocation, thread-safety characteristics, and so on. Functions that depend on these capabilities must use another technique to determine the correct code path to use for a given type. We can solve this sort of problem by associating types with custom traits that indicate what capabilities are provided by a given type.
First, assume that a compatible trait, abcd::RequiresLockTrait, has been defined that indicates that a type's methods must not be called unless a known lock is first acquired:
  namespace abcd { template <class t_TYPE> struct RequiresLockTrait; }
The implementation of abcd::RequiresLockTrait is not shown.
Then, in package xyza, we declare a type, DoesNotRequireLockType, that can be used without acquiring the lock:
  namespace xyza {

  class DoesNotRequireLockType {
      // ...

    public:
      // CREATORS
      DoesNotRequireLockType();
          // ...
  };
Next, we declare a type, RequiresLockType, that does require the lock. We use the BSLMF_NESTED_TRAIT_DECLARATION macro to associate the type with the abcd::RequiresLockTrait trait:
  class RequiresLockType {
      // ...

    public:
      // TRAITS
      BSLMF_NESTED_TRAIT_DECLARATION(RequiresLockType,
                                     abcd::RequiresLockTrait);

      // CREATORS
      RequiresLockType();
          // ...

  };
Notice that the macro declaration is performed within the scope of the class declaration, and must be done with public scope.
Now, we declare a templatized container type, Container, that is parameterized on some ELEMENT type. If ELEMENT requires a lock, then a Container of ELEMENTs will require a lock as well. This can be expressed using the BSLMF_NESTED_TRAIT_DECLARATION_IF macro, by providing abcd::RequiresLockTrait<ELEMENT>value as the condition for associating the trait with Container.
  template <class ELEMENT>
  struct Container {
      // ...

    public:
      // TRAITS
      BSLMF_NESTED_TRAIT_DECLARATION_IF(Container, abcd::RequiresLockTrait,
                                    abcd::RequiresLockTrait<ELEMENT>::value);

      // ...
  };

  } // close package namespace
Finally, code interacting with xyza::DoesNotRequireLockType, xyza::RequiresLockType or xyza::Container objects will be able to choose the appropriate code path by checking for the abcd::RequiresLockTrait trait. See bslmf_detectnestedtrait for an example of how generic code would use such a trait.