BDE 4.14.0 Production release
|
Macros | |
#define | bslmf_EnableIf bslmf::EnableIf |
This alias is defined for backward compatibility. | |
Provide a utility to set up SFINAE conditions in type deduction.
This component defines two meta-functions, bsl::enable_if
and bslmf::EnableIf
, both of which may be used to conditionally remove (potential) template instantiations as candidates for overload resolution by causing a deduced template instantiation to fail in a way compatible with the C++ SFINAE rules.
bsl::enable_if
meets the requirements of the enable_if
template defined in the C++11 standard [meta.trans.ptr], while bslmf::EnableIf
was devised before enable_if
was standardized.
The two meta-functions provide identical functionality. Both meta-functions provide a typedef
type
that is an alias to a (template parameter) type if a (template parameter) condition is true
; otherwise, type
is not provided.
Note that bsl::enable_if
should be preferred over bslmf::EnableIf
, and in general, should be used by new components.
Because of a Visual Studio bug, described here: http://connect.microsoft.com/VisualStudio/feedback/details/332179/ the Microsoft Visual Studio compiler may not correctly associate a function declaration that uses bsl::enable_if
with that function's definition, if the definition is not inline to the declaration. This bug affects at least Visual Studio 2008 and 2010. The workaround is to implement functions using bsl::enable_if
inline with their declaration.
The following snippets of code illustrate basic use of the bsl::enable_if
meta-function. We will demonstrate how to use this utility to control overload sets with three increasingly complex examples.
Suppose that we want to implement a simple swap
function template to exchange two arbitrary values, as if defined below:
However, we want to take advantage of member-swap methods supplied by user- defined types, so we define a trait that can be customized by a class implementer to indicate that their class supports an optimized member-swap method:
Now, we implement a generic swap
function template that will invoke the member swap operation for any type that specialized our trait. The use of bsl::enable_if
to declare the result type causes an attempt to deduce the type t_TYPE
to fail unless the specified condition is true
, and this falls under the "Substitution Failure Is Not An Error" (SFINAE) clause of the C++ standard, so the compiler will look for a more suitable overload rather than fail with an error. Note that we provide two overloaded declarations that appear to differ only in their return type, which would normally raise an ambiguity error. This works, and is in fact required, in this case as the "enable-if" conditions are mutually exclusive, so that only one overload will ever be present in an overload set. Also note that the type
typedef
of bsl::enable_if
is an alias to void
when the (template parameter) type is unspecified and the (template parameter) condition value is true
.
Next, we define a simple container template, that supports an optimized swap
operation by merely swapping the internal pointer to the array of elements rather than exchanging each element:
Then, we specialize our HasMemberSwap
trait for this new container type.
Next, we implement the methods of this class:
Finally, we can test that the member-swap
method is called by the generic swap
function. Note that the following code will not compile unless the member-function swap
is used, as the copy constructor and assignment operator for the MyContainer
class template are declared as private
.
For the next example, we will demonstrate the use of the second template parameter in the bsl::enable_if
template, which serves as the "result" type if the test condition passes. Suppose that we want to write a generic function to allow us to cast between pointers of different types. If the types are polymorphic, we can use dynamic_cast to potentially cast between two seemingly unrelated types. However, if either type is not polymorphic then the attempt to use dynamic_cast would be a compile-time failure, and we must use static_cast instead.
Note that if the current compiler supports alias templates C++11 feature, we can use bsl::enable_if_t
alias to the "result" type of bsl::enable_if
meta-function, that avoids the ::type
suffix and typename
prefix in the declaration of the function return type.
Next, we define a small number of classes to demonstrate that this casting utility works correctly:
Finally, we demonstrate the correct behavior of the smart_cast utility:
The final example demonstrates controlling the selection of a constructor template in a class with (potentially) many constructors. We define a simple container template based on std::vector
that illustrates a problem that may occur when trying to call the constructor the user expects. For this example, assume we are trying to create a vector<int>
with 42
copies of the value 13
. When we pass the literal values 42
and 13
to the compiler, the "best" candidate constructor should be the template constructor that takes two arguments of the same kind, deducing that type to be int
. Unfortunately, that constructor expects those values to be of an iterator type, forming a valid range. We need to avoid calling this constructor unless the deduced type really is an iterator, otherwise a compile-error will occur trying to instantiate that constructor with an incompatible argument type. We use bsl::enable_if
to create a deduction context where SFINAE can kick in. Note that we cannot deduce the ::type
result of a meta-function, and there is no result type (as with a regular function) to decorate, so we add an extra dummy argument using a pointer type (produced from bsl::enable_if::type
) with a default null argument:
Note that there is no easy test for whether a type is an iterator, so we assume that any attempt to call a constructor with two arguments that are not fundamental (such as int
) must be passing iterators. Now that we have defined the class template, we implement its methods:
Finally, we demonstrate that the correct constructors are called when invoked with appropriate arguments:
#define bslmf_EnableIf bslmf::EnableIf |