BDE 4.14.0 Production release
|
Provide a nested declaration to associate a class with a trait.
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:
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
.
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 .
This section illustrates the intended use of this component.
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:
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:
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:
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 ELEMENT
s 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
.
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.