Provide a mapping from integral constants to unique types.
More...
Namespaces |
namespace | bslmf |
namespace | bsl |
Detailed Description
- Outline
-
-
- Purpose:
- Provide a mapping from integral constants to unique types.
-
- Classes:
-
- See also:
-
- Description:
- This component describes a simple class template,
bsl::integral_constant
, that is used to map an integer constant to a C++ type. integral_constant<t_TYPE, t_VAL>
generates a unique type for each distinct compile-time integral t_TYPE
and constant integer t_VAL
parameter. That is, instantiations with different integer types and values form distinct types, so that integral_constant<int, 0>
is a different type from integral_constant<int, 1>
, which is also distinct from integral_constant<unsigned, 1>
, and so on. This mapping of integer values to types allows for "overloading by value", i.e., multiple functions with the same name can be overloaded on the "value" of an integral_constant
argument, provided that the value is known at compile-time. The typedefs bsl::true_type
and bsl::false_type
map the predicate values true
and false
to C++ types that are frequently useful for compile-time algorithms.
-
- Usage:
- This section illustrates intended usage of this component
-
- Example 1: Compile-Time Function Dispatching:
- The most common use of this structure is to perform compile-time function dispatching based on a compile-time calculation. Often the calculation is nothing more than a simple predicate, allowing us to select one of two functions based on whether the predicate holds. The following function,
doSomething
, uses a fast implementation (e.g., using memcpy
) if the parameterized type allows for such operations, otherwise it will use a more generic and slower implementation (e.g., using the copy constructor). This example uses the types true_type
and false_type
, which are simple typedefs for integral_constant<bool, true>
and integral_constant<bool, false>
, respectively. For some parameter types, the fast version of doSomethingImp
is not legal. The power of this approach is that the compiler will not attempt semantic analysis on the implementation that does not match the appropriate integral_constant
argument. int main()
{
int r;
int i;
r = doSomething<false>(&i);
assert(55 == r);
double m;
r = doSomething<true>(&m);
assert(11 == r);
return 0;
}
-
- Example 2: Base Class For Metafunctions:
- Hard-coding the value of an
integral_constant
is not especially useful. Rather, integral_constant
is typically used as the base class for "metafunction" classes, classes that yield the value of compile-time properties, including properties that are associated with types, rather than with values. For example, the following metafunction can be used at compile time to determine whether a type is a floating point type: template <class t_TYPE> struct IsFloatingPoint : bsl::false_type { };
template <> struct IsFloatingPoint<float> : bsl::true_type { };
template <> struct IsFloatingPoint<double> : bsl::true_type { };
template <> struct IsFloatingPoint<long double> : bsl::true_type { };
The value IsFloatingPoint<int>value
is false and IsFloatingPoint<double>value
is true. The integral_constant
base class has a member type, type
, that refers to itself and is inherited by IsFloatingPoint
. Thus IsFloatingPoint<float>type
is true_type
and IsFloatingPoint<char>type
is false_type
. IsFloatingPoint
is an a member of a common category of metafunctions known as "type traits" because they express certain properties (traits) of a type. Using this metafunction, we can rewrite the doSomething
function from first example so that it does not require the user to specify the IsSlow
template argument: template <class t_T>
int doSomething2(t_T *t)
{
const bool isSlow = IsFloatingPoint<t_T>::value;
return doSomethingImp(t, bsl::integral_constant<bool, isSlow>());
}
int main()
{
int r;
int i;
r = doSomething2(&i);
assert(55 == r);
double m;
r = doSomething2(&m);
assert(11 == r);
return 0;
}