Doc. no.: J16/02-0003 = WG21/N1345

Date: 07 March 2002

Project: Programming Language C++

Wiki: http://www.research.att.com/~austern/cgi-bin/wiki?TypeTraits

Reply to: John Maddock <*john_maddock@compuserve.com*>

This proposal forms part of the "infrastructure" of the standard library; it attempts to standardize templates that are often reinvented as bespoke solutions. These templates may be used by the end user, and are often used heavily by library implementers, including those who are writing third party libraries. There are three main use cases that help explain the motivation behind this proposal:

Sometimes templates are not quite as "generic" as one would wish. The problem is that not all types are created equally, implying that some categories of types may need special handling. One example of this is a version of std::pair that can hold reference types[1]. The boost compressed_pair class[2] is a more advanced example of this; as well as being able to hold reference types, it will inherit from, rather than contain, empty classes in order to take advantage of the "zero sized base class optimisation".

Often there is a contract that the template parameters to a class or function must obey. Usually if the template argument does not conform to the contract then the template will fail to compile. Often in such cases the position of the error may be deep inside several layers of template code, and it is often not at all easy for the user to deduce what the problem is, and whether it is their problem or the library's. One solution proposed for this is the idea of concept-checks[3], however a simpler solution is often possible using a static assertion[4]. For example the following code uses the boost type traits library to insist that the iterator arguments have random access semantics; if an error occurs then it will be generated early on in the procedure being instantiated, and can be commented with a description of the problem:

#include <iterator> #include <boost/static_assert.hpp> #include <boost/type_traits.hpp> template <class RandomAccessIterator > RandomAccessIterator foo(RandomAccessIterator from, RandomAccessIterator to) { // this template can only be used with // random access iterators, attempting to // use some other iterator type will result in // an error message here: typedef typename std::iterator_traits <RandomAccessIterator>::iterator_category cat; typedef int this_is_a_static_assertion[ ::boost::is_convertible< cat*, std::random_access_iterator_tag* >::value ? 1 : -1]; // // detail goes here... // return from; }

Static assertions do not form part of this proposal, however they could easily form part of another proposal.

The classic example here is
the algorithm `std::copy`

; if the types being copied
are POD's, then `std::memcpy`

can be used to copy the
data, rather than a slower "object by object" copy. The
boost library has one example of this approach[1].
However this is by no means the only example: the SGI standard
library[7] uses a type traits mechanism to
achieve the same effect, while the Dinkumware standard library
uses a function overloading approach to dispatch to the correct ```
std::copy
```

implementation. The fact that several vendors have
reinvented this technique suggests that this is an area ripe for
standardisation. It should be noted that while it is easiest to
give examples of traits-based optimisations from the standard
library, both third party libraries and user code can (and do)
make use of these techniques. In the boost libraries for example,
17 of 57 top level headers make use of boost's type traits code
either directly or indirectly.

This is basically a pure extension, it does not require any modification to existing standard library headers, and does not require any core language changes. However some of the templates listed in this proposal can not be fully implemented without some help from the compiler. The proposed text does not specify how this help is provided, and it is possible to provide an implementation that almost conforms to the semantics given, without compiler help (see the boost reference implementation[5]). Those templates that benefit from compiler help are noted below.

There are two key design decisions to be made in this proposal:

The boost type traits library (and this proposal) uses a
separate traits class for each *trait*, where as, for
example, both Loki[6] and the SGI type traits
library[7] use a single type_traits class
with multiple members. There are a number of advantages to the
separate traits class approach:

- The library contains traits classes both to describe the properties of types, and to transform one type into another. There are also many more traits represented here than there are in competing libraries that use a single "type_traits" class (in other words a single class would be overly complex).
- This approach is extensible - it is easy to add new traits classes using the methodology shown. This is particularly important for type transformations, where user defined transformations may be written to extend the library. Also new traits that describe type properties may be added by refining, combining or extending the standard traits provided by this library. In other words we define a set of concepts to which each traits class must conform.
- Experience suggests that this approach is easier to maintain - some of the traits classes described here have non-trivial implementations - it is often easier to isolate the trickier cases in their own headers for ease of maintenance.
- Separate traits classes allow each trait to be isolated into a separate header. This proposal splits the traits classes into three headers (<type_traits>, <type_compare> and <type_transform>), but an implementation might use more (internally), to allow selective reuse of only those parts of the type traits library that are needed for a particular class/function implementation.
- Separate traits classes may be used as "compile time predicates" to metaprogramming libraries, for example with algorithms that operate on type lists[8].

Finally it should be noted that Loki's author has shifted away from a single type_traits class and towards separate classes in a type_traits namespace[9].

The boost type traits library (and this proposal) uses a ```
static
const bool
```

to represent each true/false condition, where
as the SGI type traits library[7] uses a type
(__true_type or __false_type). The use of a type is more
convenient for use with function overloading, however the use of
an integral constant expression makes it much easier to combine
traits using logical expressions - something that has been often
found to be necessary during the development of the boost library.
In addition it is possible to convert a value to a type more
easily than a type can be converted to a value. In most cases
though conversion to a type should not be necessary - for example
the std::copy optimisation example does not require this:

// // copy: // same semantics as std::copy // calls memcpy where appropriate. // namespace detail{ template <bool b> struct copier { template<typename I1, typename I2> static I2 do_copy(I1 first, I1 last, I2 out) { while(first != last) { *out = *first; ++out; ++first; } return out; } }; template <> struct copier<true> { template<typename I1, typename I2> static I2* do_copy(I1* first, I1* last, I2* out) { memcpy(out, first, (last-first)*sizeof(I2)); return out+(last-first); } }; } template<typename I1, typename I2> inline I2 copy(I1 first, I1 last, I2 out) { typedef typename boost::remove_cv<typename std::iterator_traits<I1>::value_type>::type v1_t; typedef typename boost::remove_cv<typename std::iterator_traits<I2>::value_type>::type v2_t; return detail::copier< ::boost::is_same<v1_t, v2_t>::value && ::boost::is_pointer<I1>::value && ::boost::is_pointer<I2>::value && ::boost::has_trivial_assign<v1_t>::value >::do_copy(first, last, out); }

There is one potential problem with integral constant members that should be raised: these require an out of line definition as well as an inline initialisation (but see issues 48 and 82). One implementation strategy that avoids the problem of having to provide lots of definitions for these static members, would be to have the traits classes inherit from a common base class:

template <bool b> struct boolian_traits{ static const bool value = b; }; template <bool b> bool boolian_traits<b>::value; typedef boolian_traits<true> true_type; typedef boolian_traits<false> false_type; template <class T> struct is_void : public false_type {}; template <> struct is_void<void> : public true_type {}; // etc

This does not form part of this proposal, and this particular
issue is ignored in the boost library, however there may be
sufficient merit to this scheme to make it worth while adding to
the proposed text. This scheme also makes it trivial to select a
function overload based on whether a traits class inherits from `true_type`

or `false_type`

.

Perhaps the most difficult part of this proposal is deciding which traits classes should be included. The boost type traits library has undergone several revisions, with some templates being removed and others added. This proposal includes all of the current boost type traits classes along with a small number of others that are motivated by Loki[6]. The assumption is that the committee will find it easier to strike out templates from the proposal, than to add new templates (although the latter isn't necessarily ruled out). Some specific comments that have been made include:

From Andrei Alexandrescu:

"I understand the symmetry argument for adding add_const, add_volatile, add_cv, and add_pointer, however I would argue in favor of eliminating them. The language-provided equivalents are just simpler and nicer."

The names chosen for these templates is inevitably somewhat arbitrary, it may be that some could be better named:

From Howard Hinnant:

"

`template <class T> struct is_float;`

I think is_floating is a better name. Since we have a built-in type named float, I'm not sure if is_float refers to all floating types or just to float. It makes me wonder if there is also an is_double. As this library closely mirrors 3.9 [basic.types], and 3.9.1/8 refers to these types as "floating point", then is_floating_point might be another good name."

There have been one or two requests that haven't made it into the proposed text, mainly because these are templates that either don't sit well into the current design structure, or because they're usefulness isn't clear. These are documented here in case the committee wants to discuss and/or add these to the text.

From Dave Abrahams:

"Here's another one we need:

`has_common_base_class<T,U>::value`

This is the one which allows us to explicitly construct empty classes on top of one another. I suppose you could argue that the compiler should just do this automatically with the empty base optimization, but the ABIs of many compilers are now fixed and they will never (for practical purposes) be able to do it."

From Andrei Alexandrescu:

"An important trait that's missing is the transformation same_align_pod, which would yield a POD type with the same alignment requirements as the passed-in type. This type would allow one to build a union that obeys specific alignment requirements."

The following templates require compiler support in order to be implemented:

template <class T> struct is_class; template <class T> struct is_union; template <class T> struct is_polymorphic;

The following template has an implementation that is likely to be dependent upon the above:

template <class T> struct is_empty;

The following templates do not require compiler support in order to conform to the letter of this proposal, however they greatly benefit from having such support:

template <class T> struct has_trivial_constructor; template <class T> struct has_trivial_copy; template <class T> struct has_trivial_assign; template <class T> struct has_trivial_destructor; template <class T> struct has_nothrow_construct; template <class T> struct has_nothrow_copy; template <class T> struct has_nothrow_assign; template <class T> struct is_POD; template <class T> struct is_empty;

The mechanism of compiler support is not given in the proposal text, however several people have asked that this be specified, and there are a number of possibilities for this:

- The mechanism is left unspecified - it is up to each individual implemention to decide how best to support these templates - this option has the disadvantage that portable standard library implementations become much more difficult than they would otherwise be.
- For each template that requires compiler support, define
an associated operator (
`__is_class__`

,`__is_union__`

etc) that returns a Boolean integral constant expression giving the value for that trait. The main disadvantage of this approach is that which templates have compiler support has to be fixed in advance; so for example, we can't decide to provide compiler support for`is_pointer`

in order to provide extra support for compiler specific (and non-standard) pointer types. In addition each trait has to be documented twice - once for the template class, and once for its associated operator. - Define a single operator (
`__traits_of__`

) which returns an integral constant expression bitmask, containing the traits of that type. Like option 2, this requires duplicating the documentation of each trait. - Provide compiler support for the traits classes directly:
when a type traits template is to be instantiated, look
first for matching full or partial specialisations of
that template, if none is found and the compiler would
normally instantiate the primary template, instead
generate (and use) a full specialisation based on the
compiler's knowledge of the template and its template
argument(s). This option allows compiler independence for
library vendors, while at the same time allowing compiler
vendors to tailor the extent of their support for type
traits. This option also has precedent in the way in
which SGI's compiler handles their
`__type_traits`

class template.

Since it is unclear which (if any) of these options should be adopted, some guidance from both compiler vendors and library authors, on the best way to handle type traits compiler support, would be welcome.

This clause describes components used by C++ programs, particularly in templates, to: support the widest possible range of types, to optimise template code usage, and to detect type related user errors.

The type library provides three facilities: access to the properties of a particular type, access to the relationships (if any) between two types, and transformations from one type to another; as summarised in table TT1

Clause | Header |

Requirements | |

Unary type traits | <type_traits> |

Relationships between types | <type_compare> |

Transformations between types | <type_transform> |

In table TT2, X is a class template that is a unary type trait and T is any arbitrary type.

Expression | Return type | Requirement |

X<T>::value | bool | An integral constant expression that is true if T has the specified trait, and false otherwise. |

In table TT3, X is a class template that is a binary type trait and T and U are any arbitrary types.

Expression | Return type | Requirement |

X<T,U>::value | bool | An integral constant expression that is true if T is related to U by the relation specified, and false otherwise. |

In table TT4, X is a class template that is a transformation trait and T is any arbitrary type.

Expression | Requirement |

X<T>::type | The result is a type that is the result of applying transformation X to type T. |

This sub-clause contains templates that may be used to query the properties of a type at compile time.

All of the class templates defined in this header satisfy the UnaryTypeTrait requirements.

namespace std{ // Primary type categories: template <class T> struct is_void; template <class T> struct is_integral; template <class T> struct is_float; template <class T> struct is_array; template <class T> struct is_pointer; template <class T> struct is_reference; template <class T> struct is_member_pointer; template <class T> struct is_enum; template <class T> struct is_union; template <class T> struct is_class; template <class T> struct is_function; // composite type categories: template <class T> struct is_arithmetic; template <class T> struct is_fundamental; template <class T> struct is_object; template <class T> struct is_scalar; template <class T> struct is_compound; // type properties: template <class T> struct is_const; template <class T> struct is_volatile; template <class T> struct is_POD; template <class T> struct is_empty; template <class T> struct is_polymorphic; template <class T> struct has_trivial_constructor; template <class T> struct has_trivial_copy; template <class T> struct has_trivial_assign; template <class T> struct has_trivial_destructor; template <class T> struct has_nothrow_construct; template <class T> struct has_nothrow_copy; template <class T> struct has_nothrow_assign; } // namespace std

Primary Type Categories

The primary type categories correspond to the descriptions given in section 3.9.

For any given type T, exactly one of the primary type
categories shall have its member `value`

evaluate to
true.

For any given type T, the result of applying one of these
templates to `T`

, and to `const volatile T`

shall yield the same result.

It is unspecified whether any of these templates have any full or partial specialisations defined. It is permitted for the user to specialise any of these templates on a user-defined type, provided the semantics of the specialisation match those given for the template in its description.

Author's Note: Some of these templates require help from the compiler, specifically: is_union and is_class. However, this list can be trimmed down; only one of is_union and is_class need compiler help, since the other can then be implemented by a process of elimination.

template <class T> struct is_void { static const bool value = implementation_defined; };

`value`

: defined to be true if T is void or a cv-qualified
void.

template <class T> struct is_integral { static const bool value = implementation_defined; };

`value`

: defined to be true if T is an integral
type (3.9.1).

template <class T> struct is_float { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a floating
point type (3.9.1).

template <class T> struct is_array { static const bool value = implementation_defined; };

`value`

: defined to be true if T is an array type (3.9.2).

template <class T> struct is_pointer { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a pointer type
(3.9.2), this includes all function pointer types, but not
pointers to members or member functions.

template <class T> struct is_reference { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a reference
type (3.9.2), this includes all reference to function types.

template <class T> struct is_member_pointer { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a pointer to
member or a pointer to member function.

template <class T> struct is_enum { static const bool value = implementation_defined; };

`value`

: defined to be true if T is an enumeration
type (3.9.2).

Author's Note: It may not be immediately obvious how to implement this template without compiler help. In fact enumeration types may be detected by virtue of the fact that they are not integral types, but do have a non-user defined conversion to type

int(seeboost type_traits implementation[5]).

template <class T> struct is_union { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a union type (3.9.2).

Author's Note: This is the only template in this proposal for which there is no known (or foreseeable) use; except that it can be used in the implementation of is_class, and that its omission would imply that there are some types that do not fit into any of the categories given.

template <class T> struct is_class { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a class type (3.9.2).

template <class T> struct is_function { static const bool value = implementation_defined; };

`value`

: defined to be true if T is a function type
(3.9.2).

[Author's Note- The template is_function can be implemented as follows:

template <class T> struct is_function{ static const bool value = !is_convertible<T*, const voilatile void*>::value; }; template <class T> struct is_function<T&>{ static const bool value = false; };

Function types (as distinct from function pointers or references) can be introduced either via a typedef or via template argument deduction:

#include <cassert> #include <type_traits> typedef int function_type(int); template <class T> void deduce_function_type(T& t) { assert(std::is_function<T>::value); } void foo(){} int main() { assert(std::is_function< function_type>::value); deduce_function_type(foo); return 0; }

- Author's note].

These templates provide convenient compositions of the primary type categories, corresponding to the descriptions given in section 3.9.

For any given type T, the result of applying one of these
templates to `T`

, and to `const volatile T`

shall yield the same result.

It is unspecified whether any of these templates have any full or partial specialisations defined. It is permitted for the user to specialise any of these templates on a user-defined type, provided the semantics of the specialisation match those given for the template in its description.

template <class T> struct is_arithmetic { static const bool value = is_integral<T>::value || is_float<T>::value; };

`value`

: defined to be true if T is an arithmetic
type (3.9.1).

template <class T> struct is_fundamental{ static const bool value = is_integral<T>::value || is_float<T>::value || is_void<T>::value; };

`value`

: defined to be true if T is a fundamental
type (3.9.1).

template <class T> struct is_object{ static const bool value = !(is_function<T>::value || is_reference<T>::value || is_void<T>::value); };

`value`

: defined to be true if T is an object type
(3.9).

template <class T> struct is_scalar{ static const bool value = is_arithmetic<T>::value || is_enum<T>::value || is_pointer<T>::value || is_member_pointer<T>::value; };

`value`

: defined to be true if T is a scalar type (3.9).

template <class T> struct is_compound{ static const bool value = is_array<T>::value || is_function<T>::value || is_pointer<T>::value || is_reference<T>::value || is_enum<T>::value || is_union<T>::value || is_class<T>::value || is_member_pointer<T>::value; };

`value`

: defined to be true if T is a compound type
(3.9.2).

These templates provide access to some of the more important properties of types; they reveal information which is available to the compiler, but which would not otherwise be detectable in C++ code.

Except where specified, it is undefined whether any of these templates have any full or partial specialisations defined. It is permitted for the user to specialise any of these templates on a user-defined type, provided the semantics of the specialisation match those given for the template in its description.

The template `is_const`

shall have its member `value`

defined to be true for all types `const T`

, the
template `is_volatile`

shall have its member `value`

defined to be true for all `volatile T`

. It is
unspecified whether the remaining templates ever define their `value`

members to be true, except that the following conditions shall
always hold true for all T:

has_nothrow_*<T>::value == has_nothrow_*<remove_bounds<T>::type>::value has_nothrow_*<T>::value >= has_trivial_*<T>::value has_trivial_*<T>::value == has_trivial_*<remove_bounds<T>::type>::value has_trivial_*<T>::value >= is_POD<T>::value is_POD<T>::value == is_POD<remove_bounds<T>::type>::value is_POD<T>::value >= (is_scalar<T>::value || is_void<T>::value)

Author's Note: is this the best and/or correct way to specify these relationships? Are volatile qualified types POD's? Section 3.9p10 says clearly that they are - however is a volatile qualifier compatible with applying memcpy to the type as in section 3.9p2?

template <class T> struct is_const{ static const bool value = implementation_defined; };

`value`

: defined to be true if T is const-qualified
(3.9.3).

template <class T> struct is_volatile{ static const bool value = implementation_defined; };

`value`

: defined to be true if T is volatile-qualified
(3.9.3).

template <class T> struct is_POD{ static const bool value = implementation_defined; };

`value`

: defined to be true if T is a POD type (3.9).

template <class T> struct is_empty{ static const bool value = implementation_defined; };

`value`

: defined to be true if T is an empty class
(10).

Author's Note: Although it is unspecified whether there is any T for which is_empty<T>::value is true, in practice it is possible to implement is_empty so that it gives the correct answer, provided that the compiler implements zero sized empty base classes - see the boost reference implementation[5].

template <class T> struct is_polymorphic{ static const bool value = implementation_defined; };

`value`

: defined to be true if T is a polymorphic
class (10.3).

template <class T> struct has_trivial_constructor{ static const bool value = implementation_defined; };

`value`

: defined to be true if the default
constructor for T is trivial(12.1).

template <class T> struct has_trivial_copy{ static const bool value = implementation_defined; };

`value`

: defined to be true if the copy constructor
for T is trivial (12.8).

template <class T> struct has_trivial_assign{ static const bool value = implementation_defined; };

`value`

: defined to be true if the assignment
operator for T is trivial (12.8).

template <class T> struct has_trivial_destructor{ static const bool value = implementation_defined; };

`value`

: defined to be true if the destructor for T
is trivial (12.4).

Author's Note: Although it is unspecified whether there is any T for which has_trivial_*<T>::value is true, in practice it is possible to implement these templates so that they do give the correct answer with just a little compiler help. For example the SGI compiler provides automatic specialisations of the SGI __type_traits class[7], the boost type traits classes hook into this mechanism, converting SGI style type traits to the boost style[5].

template <class T> struct has_nothrow_construct{ static const bool value = implementation_defined; };

`value`

: defined to be true if the default
constructor for T is guaranteed not to throw.

template <class T> struct has_nothrow_copy{ static const bool value = implementation_defined; };

`value`

: defined to be true if the copy constructor
for T is guaranteed not to throw.

template <class T> struct has_nothrow_assign{ static const bool value = implementation_defined; };

`value`

: defined to be true if the assignment
operator for T is guaranteed not to throw.

This sub-clause contains templates that may be used to query the relationships between two types at compile time.

All of the templates in this header satisfy the BinaryTypeTrait requirements.

namespace std{ // type relations: template <class T, class U> struct is_same; template <class From, class To> struct is_convertible; template <class Base, class Derived> struct is_base_and_derived; } // namespace std

template <class T, class U> struct is_same{ static const bool value = false; }; template <class T> struct is_same<T,T>{ static const bool value = true; };

`value`

: defined to be true if T and U are the same
type.

template <class From, class To> struct is_convertible { static const bool value = implementation_defined; };

`value`

: defined to be true only if type `From`

is implicitly-convertible to type `To`

(4).

```
template < class Base, class Derived> struct is_base_and_derived {
static const bool value =
````is_convertible<Derived*,Base*>::value`

;
};

`value`

: defined to be true only if type `Base`

is a base class of type `Derived`

(10). Equivalent to `is_convertible<Derived*,Base*>::value`

.

This sub-clause contains templates that may be used to transform one type to another following some predefined rule.

All of the templates in this header satisfy the TransformationTrait requirements.

namespace std{ // const-volatile modifications: template <class T> struct remove_const; template <class T> struct remove_volatile; template <class T> struct remove_cv; template <class T> struct add_const; template <class T> struct add_volatile; template <class T> struct add_cv; // reference modifications: template <class T> struct remove_reference; template <class T> struct add_reference; // array modifications: template <class T> struct remove_bounds; // pointer modifications: template <class T> struct remove_pointer; template <class T> struct add_pointer; } // namespace std

template <class T> struct remove_const{ typedef T type; }; template <class T> struct remove_const<T const>{ typedef T type; };

`type`

: defined to be a type that is the same as T,
except that any top level const-qualifier has been removed. For
example: `remove_const<const volatile int>::type`

evaluates
to `volatile int,`

where as ```
remove_const<const
int*>
```

is `const int*`

.

template <class T> struct remove_volatile{ typedef T type; }; template <class T> struct remove_volatile<T volatile>{ typedef T type; };

`type`

: defined to be a type that is the same as T,
except that any top level volatile-qualifier has been removed.
For example: `remove_const<const volatile int>::type`

evaluates
to `const int,`

where as ```
remove_const<volatile
int*>
```

is `volatile int*`

.

template <class T> struct remove_cv{ typedef typename remove_const<typename remove_volatile<T>::type>::type type; };

`type`

: defined to be a type that is the same as T,
except that any top level cv-qualifiers have been removed. For
example: `remove_cv<const volatile int>::type`

evaluates
to `int,`

where as ```
remove_cv<const volatile
int*>
```

is `const volatile int*`

.

template <class T> struct add_const{ typedef T const type; };

`type`

: defined to be a type that is the same as T,
except that a top level const-qualifier has been added, provided
that T is not already const-qualified or a reference or function
type.

template <class T> struct add_volatile{ typedef T volatile type; };

`type`

: defined to be a type that is the same as T,
except that a top level volatile-qualifier has been added,
provided that T is not already volatile-qualified or a reference
or function type.

template <class T> struct add_cv{ typedef T const volatile type; };

`type`

: defined to be a type that is the same as T,
except that top level const- and volatile-qualifiers have been
added, provided that T is not already const-volatile-qualified or
a reference or function type.

Author's Note: superficially the add_const, add_volatile and add_cv classes are irrelevant, since, for example,`add_const<T>::type`

is the same as`T const`

, for all T (currently this does not apply to function types - but issue 295 addresses this). However the experience from boost is that several users have asked for these templates to be present in the library for the following reasons: (a) Some users find these more explicit - when combining transformation templates in particular, users like the kind of "built in documentation" that these templates provide. (b) Not all users are aware that cv-qualifying a reference is allowed and has no effect, or that cv-qualifying a type that is already cv-qualified is allowed and has no effect. (c) Compilers may emit warnings when cv-qualifying a type that is a reference, or already has a cv-qualifier, these templates can be implemented such that these messages are suppressed in these cases.

template <class T> struct remove_reference{ typedef T type; }; template <class T> struct remove_reference<T&>{ typedef T type; };

`type`

: defined to be a type that is the same as T,
except any reference qualifier has been removed.

template <class T> struct add_reference{ typedef T& type; }; template <class T> struct add_reference<T&>{ typedef T& type; };

`type`

: defined to be a type that is the same as
T&.

Author's Note: the add_reference template was one of the original motivations behind the boost type traits library. However the resolution to issue 106 makes the template appear largely redundant. In spite of that add_reference may well be useful in suppressing compiler warnings when inadvertently creating references to references in template code.

template <class T> struct remove_bounds{ typedef T type; }; template <class T, std::size_t N> struct remove_bounds<T[N]>{ typedef T type; };

`type`

: defined to be a type that is the same as T,
except any top level array bounds have been removed.

Author's Note: there is no add_bounds template, basically because there are several different meanings that could be applied to this. For example what happens when you add bounds to a reference type, and if you add bounds to a pointer should you get an array of pointers, or an array of the thing being pointed to. For these reasons the author believes that it is better to deliberately omit this template, and leave it to users to define their own add_bounds template if they need it, that gives the particular semantics that they require.

template <class T> struct remove_pointer{ typedef T type; }; template <class T> struct remove_pointer<T*>{ typedef T type; }; template <class T> struct remove_pointer<T* const>{ typedef T type; }; template <class T> struct remove_pointer<T* volatile>{ typedef T type; }; template <class T> struct remove_pointer<T* const volatile>{ typedef T type; };

`type`

: defined to be a type that is the same as T,
except any top level indirection has been removed.

template <class T> struct add_pointer{ typedef typename remove_bounds<typename remove_reference<T>::type>::type* type; };

`type`

: defined to be a type that is the result of
the expression `&t`

, where `t `

is an
instance of T.

- John Maddock and Steve Cleary, "C++ Type Traits", Dr Dobbs Journal, October 2000.
- Steve Cleary, Beman Dawes, Howard Hinnant and John Maddock, "compressed_pair", Boost library documentation.
- Jeremy Siek, "Concept Checking", C++ Template Workshop 2000.
- John Maddock, "static assert", Boost library documentation.
- Steve Cleary, Beman Dawes, Aleksey Gurtovoy, Howard Hinnant, Jesse Jones, Mat Marcus, John Maddock and Jeremy Siek, "Type traits", Boost library documentation.
- Andrei Alexandrescu, "Modern C++ Design: Generic Programming and Design Patterns Applied", Addison-Wesley, 2001.
- SGI, "The SGI standard template library".
- Emily Winch, Heterogenous lists of named objects, Second C++ Template Programming Workshop 2001.
- Andrei Alexandrescu, "Generic<Programming>: Typed Buffers (II)", Oct CUJ C++ Experts, 2001.

The author is particularly indebted to everyone who as worked on the boost type traits library[5], but also to David Abrahams, Darin Adler, Beman Dawes and Emily Winch for their helpful comments on an early draft of this document.