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

Macros

#define BSLMF_TYPEIDENTITY_T(...)    typename ::bsl::type_identity<__VA_ARGS__ >::type
 

Detailed Description

Outline

Purpose

Provide a template metafunction that returns its argument.

Classes

Macros

See also

Description

This component provides a trivial template metafunction class, bsl::type_identity that takes one type template argument and produces the argument type as its result; i.e., bsl::type_identity<t_TYPE>::type is simply an alias for t_TYPE. This metafunction is used in situations where a no-op metafunction is desired or where template type deduction should be suppressed. This component also provides, for C++11 and later, an alias, bsl::type_identity_t such that bsl::type_identity_t<t_TYPE> is short hand for typename bsl::type_identity<t_TYPE>::type.

The templates in this component have identical functionality to the standard templates, std::type_identity and std::type_identity_t defined in the <type_traits> header starting with C++20.

Usage

Example 1: Requiring explicit function template arguments

A function template can often deduce the types of its arguments, but sometimes we wish to prevent such deduction and require the user to supply the desired type explicitly. In this example, we'll declare a cast function, implicitCast, that is invoked implicitCast<T>(arg). The goal is cast the arg to type T, but only if arg is implicitly convertible to T.

First, we'll define a type TestType, that is implicitly convertible from int but only explicitly convertible from const char *:

struct TestType {
TestType(int) { } // IMPLICIT
explicit TestType(const char*) { }
};

Next, we'll define implicitCastNAIVE, a naive and insufficient attempt at defining implicitCast:

template <class t_TYPE>
t_TYPE implicitCastNAIVE(t_TYPE arg)
{
return arg;
}

Next, we try to use implicitCastNAIVE. The first invocation below correctly casts an int to TestType. The second invocation should, and does, fail to compile because const char* is not implicitly convertible to TestType. In the third invocation, we forgot the <TestType> template parameter. Surprisingly (for the user), the code compiles anyway because implicitCastNAIVE deduced t_TYPE to be const char* and returns its argument unmodified, i.e., doing no casting whatsoever:

TestType v1(implicitCastNAIVE<TestType>(5)); // OK
TestType v2(implicitCastNAIVE<TestType>("bye")); // Fails correctly.
TestType v3(implicitCastNAIVE("hello")); // Succeeds incorrectly.

Now, we implement implicitCast correctly, using bsl::type_identity to prevent implicit template-argument deduction:

template <class t_TYPE>
t_TYPE implicitCast(typename bsl::type_identity<t_TYPE>::type arg)
{
return arg;
}
t_TYPE type
Definition bslmf_typeidentity.h:216

Finally, we try using implicitCast both correctly and incorrectly. As before, the first invocation below correctly casts an int to TestType and second invocation correctly fails to compile. Unlike the implicitCastNAIVE example, however, the third invocation correctly fails to compile because t_TYPE is not deduceable for a parameter of type bsl::type_identity<t_TYPE>::type.

TestType v4(implicitCast<TestType>(5)); // OK
TestType v5(implicitCast<TestType>("bye")); // Fails correctly.
TestType v6(implicitCast("hello")); // Fails correctly.

Note that typename bsl::type_identity<t_TYPE>::type can be replaced by the more concise bsl::type_identity_t<t_TYPE> (compatible with C++11 and later) or BSLMF_TYPEIDENTITY_T(t_TYPE) (compatible with all C++ versions).

Example 2: preventing ambiguous argument deduction in function templates

In this example, we illustrate how to prevent ambiguities when type deductions occurs on multiple function-template arguments. Our sample function returns a number within a range two-thirds of the way between the start and end of the range. The types of the arguments determine the type of the result.

First, we implement the function using a simple but potentially ambiguous interface:

template <class NUMTYPE>
inline NUMTYPE twoThirdsOfTheWay1(NUMTYPE first, NUMTYPE last)
{
return first + (last - first) * 2 / 3;
}

Now, try to invoke our function. We get into trouble when the two arguments have different types; the compiler is unable to deduce a single NUMTYPE:

int i1 = twoThirdsOfTheWay1(0, 6); // OK, 'NUMTYPE' is 'int'
double d1 = twoThirdsOfTheWay1(0, 0.75); // Ambiguous: 'int' vs 'double'

Next, we try again, this time using bsl::type_identity to suppress type deduction on the first argument. The first argument, rather than the second argument is chosen for this treatment because the first argument of a numeric range is so often 0, which happens to be an int but is often used, without losing precision, with unsigned, float, and double values. The second argument, conversely, usually carries a significant value whose type is important:

template <class NUMTYPE>
inline NUMTYPE twoThirdsOfTheWay(BSLMF_TYPEIDENTITY_T(NUMTYPE) first,
NUMTYPE last)
{
return first + (last - first) * 2 / 3;
}
int i2 = twoThirdsOfTheWay(0, 6); // OK, 'NUMTYPE' is 'int'
double d2 = twoThirdsOfTheWay(0, 0.75); // OK, 'NUMTYPE' is 'double'
#define BSLMF_TYPEIDENTITY_T(...)
Definition bslmf_typeidentity.h:253

Finally, we verify that our twoThirdsOfTheWay function worked correctly:

int main()
{
assert(4 == i2);
assert(0.5 == d2);
assert(0 == twoThirdsOfTheWay(4U, -2));
}

Macro Definition Documentation

◆ BSLMF_TYPEIDENTITY_T

#define BSLMF_TYPEIDENTITY_T (   ...)     typename ::bsl::type_identity<__VA_ARGS__ >::type

Metafunction returning its type argument unchanged. Shorthand alias for typename type_identity<...>::type. The type argument to this macro must be a dependent type of the function template or class template in which it is used, i.e., a template parameter or type related to a template parameter. Note that this macro exists for compatibility with C++03; for C++11 and later compilers, bsl::type_identity_t is preferred.

Implementation note: space before closing > is important to avoid >> issues in C++03.