[library Boost.TypeTraits
[copyright 2000 2005 Adobe Systems Inc, David Abrahams, Steve Cleary,
Beman Dawes, Aleksey Gurtovoy, Howard Hinnant, Jesse Jones, Mat Marcus,
Itay Maman, John Maddock, Thorsten Ottosen, Robert Ramey and Jeremy Siek]
[purpose Meta-programming support library]
[license
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt
)
]
[authors [authors, various]]
[category template]
[category generic]
[last-revision $Date: 2007/05/09 17:20:56 $]
]
[def __boost_root ../../../../]
[def __tof '''true_type-or-false_type''']
[def __below '''see-below''']
[def __true_type [link boost_typetraits.integral_constant true_type]]
[def __false_type [link boost_typetraits.integral_constant false_type]]
[def __integral_constant [link boost_typetraits.integral_constant integral_constant]]
[def __inherit [*Inherits:]]
[def __std_ref [*C++ Standard Reference:]]
[def __header [*Header:]]
[def __compat [*Compiler Compatibility:]]
[def __examples [*Examples:]]
[def __type [*type:]]
[def __transform_workaround [link transform.broken_compiler_workarounds_ compiler workarounds]]
[def __intrinsics [link boost_typetraits.intrinsics intrinsics]]
[def __is_void [link boost_typetraits.is_void is_void]]
[def __is_integral [link boost_typetraits.is_integral is_integral]]
[def __is_floating_point [link boost_typetraits.is_floating_point is_floating_point]]
[def __is_pointer [link boost_typetraits.is_pointer is_pointer]]
[def __is_reference [link boost_typetraits.is_reference is_reference]]
[def __is_member_pointer [link boost_typetraits.is_member_pointer is_member_pointer]]
[def __is_array [link boost_typetraits.is_array is_array]]
[def __is_union [link boost_typetraits.is_union is_union]]
[def __is_class [link boost_typetraits.is_class is_class]]
[def __is_enum [link boost_typetraits.is_enum is_enum]]
[def __is_enum [link boost_typetraits.is_enum is_enum]]
[def __is_function [link boost_typetraits.is_function is_function]]
[def __is_arithmetic [link boost_typetraits.is_arithmetic is_arithmetic]]
[def __is_fundamental [link boost_typetraits.is_fundamental is_fundamental]]
[def __is_object [link boost_typetraits.is_object is_object]]
[def __is_scalar [link boost_typetraits.is_scalar is_scalar]]
[def __is_compound [link boost_typetraits.is_compound is_compound]]
[def __is_member_function_pointer [link boost_typetraits.is_member_function_pointer is_member_function_pointer]]
[def __is_member_object_pointer [link boost_typetraits.is_member_object_pointer is_member_object_pointer]]
[def __alignment_of [link boost_typetraits.alignment_of alignment_of]]
[def __rank [link boost_typetraits.rank rank]]
[def __extent [link boost_typetraits.extent extent]]
[def __is_empty [link boost_typetraits.is_empty is_empty]]
[def __is_const [link boost_typetraits.is_const is_const]]
[def __is_volatile [link boost_typetraits.is_volatile is_volatile]]
[def __is_abstract [link boost_typetraits.is_abstract is_abstract]]
[def __is_polymorphic [link boost_typetraits.is_polymorphic is_polymorphic]]
[def __has_virtual_destructor [link boost_typetraits.has_virtual_destructor has_virtual_destructor]]
[def __is_pod [link boost_typetraits.is_pod is_pod]]
[def __has_trivial_constructor [link boost_typetraits.has_trivial_constructor has_trivial_constructor]]
[def __has_trivial_copy [link boost_typetraits.has_trivial_copy has_trivial_copy]]
[def __has_trivial_assign [link boost_typetraits.has_trivial_assign has_trivial_assign]]
[def __has_trivial_destructor [link boost_typetraits.has_trivial_destructor has_trivial_destructor]]
[def __is_stateless [link boost_typetraits.is_stateless is_stateless]]
[def __has_nothrow_constructor [link boost_typetraits.has_nothrow_constructor has_nothrow_constructor]]
[def __has_nothrow_copy [link boost_typetraits.has_nothrow_copy has_nothrow_copy]]
[def __has_nothrow_assign [link boost_typetraits.has_nothrow_assign has_nothrow_assign]]
[def __is_base_of [link boost_typetraits.is_base_of is_base_of]]
[def __is_convertible [link boost_typetraits.is_convertible is_convertible]]
[def __is_same [link boost_typetraits.is_same is_same]]
[def __remove_const [link boost_typetraits.remove_const remove_const]]
[def __remove_volatile [link boost_typetraits.remove_volatile remove_volatile]]
[def __remove_cv [link boost_typetraits.remove_cv remove_cv]]
[def __remove_reference [link boost_typetraits.remove_reference remove_reference]]
[def __remove_extent [link boost_typetraits.remove_extent remove_extent]]
[def __remove_all_extents [link boost_typetraits.remove_all_extents remove_all_extents]]
[def __remove_pointer [link boost_typetraits.remove_pointer remove_pointer]]
[def __add_reference [link boost_typetraits.add_reference add_reference]]
[def __add_pointer [link boost_typetraits.add_pointer add_pointer]]
[def __add_const [link boost_typetraits.add_const add_const]]
[def __add_volatile [link boost_typetraits.add_volatile add_volatile]]
[def __add_cv [link boost_typetraits.add_cv add_cv]]
[def __type_with_alignment [link boost_typetraits.type_with_alignment type_with_alignment]]
[def __aligned_storage [link boost_typetraits.aligned_storage aligned_storage]]
[def __function_traits [link boost_typetraits.function_traits function_traits]]
[section:intro Introduction]
This documentation is
[@http://boost-consulting.com/vault/index.php?action=downloadfile&filename=boost_type_traits-1.34.pdf&directory=PDF%20Documentation&
also available in printer-friendly PDF format].
The Boost type-traits library contains a
set of very specific traits classes, each of which encapsulate a single trait
from the C++ type system; for example, is a type a pointer or a reference type?
Or does a type have a trivial constructor, or a const-qualifier?
The type-traits classes share a unified design: each class inherits from a
the type __true_type if the type has the specified property and inherits from
__false_type otherwise.
The type-traits library also contains a set of classes that perform a
specific transformation on a type; for example, they can remove a
top-level const or volatile qualifier from a type. Each class that
performs a transformation defines a single typedef-member `type`
that is the result of the transformation.
[endsect]
[section:background Background and Tutorial]
The following is an updated version of the article "C++ Type traits"
by John Maddock and Steve Cleary that appeared in the October 2000
issue of [@http://www.ddj.com Dr Dobb's Journal].
Generic programming (writing code which works with any data type meeting a
set of requirements) has become the method of choice for providing reusable code.
However, there are times in generic programming when "generic" just isn't
good enough - sometimes the differences between types are too large for an
efficient generic implementation. This is when the traits technique
becomes important - by encapsulating those properties that need to be
considered on a type by type basis inside a traits class, we can
minimize the amount of code that has to differ from one type to another,
and maximize the amount of generic code.
Consider an example: when working with character strings, one common operation is
to determine the length of a null terminated string. Clearly it's possible to
write generic code that can do this, but it turns out that there are much more
efficient methods available: for example, the C library functions `strlen` and
`wcslen` are usually written in assembler, and with suitable hardware support
can be considerably faster than a generic version written in C++.
The authors of the C++ standard library realized this, and abstracted the
properties of `char` and `wchar_t` into the class `char_traits`. Generic code
that works with character strings can simply use `char_traits<>::length` to
determine the length of a null terminated string, safe in the knowledge
that specializations of `char_traits` will use the most appropriate method
available to them.
[h4 Type Traits]
Class `char_traits` is a classic example of a collection of type specific
properties wrapped up in a single class - what Nathan Myers termed a
/baggage class/[link background.references \[1\]]. In the Boost type-traits library, we[link background.references \[2\]] have written a
set of very specific traits classes, each of which encapsulate a single trait
from the C++ type system; for example, is a type a pointer or a reference type?
Or does a type have a trivial constructor, or a const-qualifier?
The type-traits classes share a unified design: each class inherits from a
the type __true_type if the type has the specified property and inherits from
__false_type otherwise. As we will show, these classes can be used in
generic programming to determine the properties of a given type and introduce
optimizations that are appropriate for that case.
The type-traits library also contains a set of classes that perform a
specific transformation on a type; for example, they can remove a
top-level const or volatile qualifier from a type. Each class that
performs a transformation defines a single typedef-member `type`
that is the result of the transformation. All of the type-traits
classes are defined inside namespace `boost`; for brevity, namespace-qualification
is omitted in most of the code samples given.
[h4 Implementation]
There are far too many separate classes contained in the type-traits library
to give a full implementation here - see the source code in the Boost library
for the full details - however, most of the implementation is fairly repetitive
anyway, so here we will just give you a flavor for how some of the classes are
implemented. Beginning with possibly the simplest class in the library,
`is_void` inherits from `__true_type` only if `T` is `void`.
template
struct __is_void : public __false_type{};
template <>
struct __is_void : public __true_type{};
Here we define a primary version of the template class `__is_void`, and
provide a full-specialization when `T` is `void`. While full specialization
of a template class is an important technique, sometimes we need a
solution that is halfway between a fully generic solution, and a full
specialization. This is exactly the situation for which the standards committee
defined partial template-class specialization. As an example, consider the
class `boost::is_pointer`: here we needed a primary version that handles
all the cases where T is not a pointer, and a partial specialization to
handle all the cases where T is a pointer:
template
struct __is_pointer : public __false_type{};
template
struct __is_pointer : public __true_type{};
The syntax for partial specialization is somewhat arcane and could easily
occupy an article in its own right; like full specialization, in order to
write a partial specialization for a class, you must first declare the
primary template. The partial specialization contains an extra <...> after the
class name that contains the partial specialization parameters; these define
the types that will bind to that partial specialization rather than the
default template. The rules for what can appear in a partial specialization
are somewhat convoluted, but as a rule of thumb if you can legally write two
function overloads of the form:
void foo(T);
void foo(U);
Then you can also write a partial specialization of the form:
template
class c{ /*details*/ };
template
class c{ /*details*/ };
This rule is by no means foolproof, but it is reasonably simple to remember
and close enough to the actual rule to be useful for everyday use.
As a more complex example of partial specialization consider the class
`remove_extent`. This class defines a single typedef-member `type` that
is the same type as T but with any top-level array bounds removed;
this is an example of a traits class that performs a transformation on a type:
template
struct __remove_extent
{ typedef T type; };
template
struct __remove_extent
{ typedef T type; };
The aim of `__remove_extent` is this: imagine a generic algorithm that is
passed an array type as a template parameter, `__remove_extent` provides a
means of determining the underlying type of the array. For example
`remove_extent::type` would evaluate to the type `int[5]`.
This example also shows that the number of template parameters in a
partial specialization does not have to match the number in the
default template. However, the number of parameters that appear after the
class name do have to match the number and type of the parameters in the
default template.
[h4 Optimized copy]
As an example of how the type traits classes can be used, consider the
standard library algorithm copy:
template
Iter2 copy(Iter1 first, Iter1 last, Iter2 out);
Obviously, there's no problem writing a generic version of copy that works
for all iterator types `Iter1` and `Iter2`; however, there are some
circumstances when the copy operation can best be performed by a call to
`memcpy`. In order to implement copy in terms of `memcpy` all of the
following conditions need to be met:
* Both of the iterator types `Iter1` and `Iter2` must be pointers.
* Both `Iter1` and `Iter2` must point to the same type - excluding const and
volatile-qualifiers.
* The type pointed to by `Iter1` must have a trivial assignment operator.
By trivial assignment operator we mean that the type is either a scalar type[link background.references \[3\]] or:
* The type has no user defined assignment operator.
* The type does not have any data members that are references.
* All base classes, and all data member objects must have trivial assignment operators.
If all these conditions are met then a type can be copied using `memcpy`
rather than using a compiler generated assignment operator. The type-traits
library provides a class `__has_trivial_assign`, such that
`has_trivial_assign::value` is true only if T has a trivial assignment operator.
This class "just works" for scalar types, but has to be explicitly
specialised for class/struct types that also happen to have a trivial assignment
operator. In other words if __has_trivial_assign gives the wrong answer,
it will give the "safe" wrong answer - that trivial assignment is not allowable.
The code for an optimized version of copy that uses `memcpy` where appropriate is
given in [link boost_typetraits.copy the examples]. The code begins by defining a template
function `do_copy` that performs a "slow but safe" copy. The last parameter passed
to this function may be either a `__true_type` or a `__false_type`. Following that
there is an overload of do_copy that uses `memcpy`: this time the iterators are required
to actually be pointers to the same type, and the final parameter must be a
`__true_type`. Finally, the version of `copy` calls `do_copy`, passing
`__has_trivial_assign()` as the final parameter: this will dispatch
to the optimized version where appropriate, otherwise it will call the
"slow but safe version".
[h4 Was it worth it?]
It has often been repeated in these columns that "premature optimization is the
root of all evil" [link background.references \[4\]]. So the question must be asked: was our optimization
premature? To put this in perspective the timings for our version of copy
compared a conventional generic copy[link background.references \[5\]] are shown in table 1.
Clearly the optimization makes a difference in this case; but, to be fair,
the timings are loaded to exclude cache miss effects - without this
accurate comparison between algorithms becomes difficult. However, perhaps
we can add a couple of caveats to the premature optimization rule:
*If you use the right algorithm for the job in the first place then optimization
will not be required; in some cases, memcpy is the right algorithm.
*If a component is going to be reused in many places by many people then
optimizations may well be worthwhile where they would not be so for a single
case - in other words, the likelihood that the optimization will be
absolutely necessary somewhere, sometime is that much higher.
Just as importantly the perceived value of the stock implementation will be
higher: there is no point standardizing an algorithm if users reject it on
the grounds that there are better, more heavily optimized versions available.
[table Time taken to copy 1000 elements using `copy` (times in micro-seconds)
[[Version] [T] [Time]]
[["Optimized" copy] [char] [0.99]]
[[Conventional copy] [char] [8.07]]
[["Optimized" copy] [int] [2.52]]
[[Conventional copy] [int] [8.02]]
]
[h4 Pair of References]
The optimized copy example shows how type traits may be used to perform
optimization decisions at compile-time. Another important usage of type traits
is to allow code to compile that otherwise would not do so unless excessive
partial specialization is used. This is possible by delegating partial
specialization to the type traits classes. Our example for this form of
usage is a pair that can hold references [link background.references \[6\]].
First, let us examine the definition of `std::pair`, omitting the
comparison operators, default constructor, and template copy constructor for
simplicity:
template
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(const T1 & nfirst, const T2 & nsecond)
:first(nfirst), second(nsecond) { }
};
Now, this "pair" cannot hold references as it currently stands, because the
constructor would require taking a reference to a reference, which is
currently illegal [link background.references \[7\]]. Let us consider what the constructor's parameters
would have to be in order to allow "pair" to hold non-reference types,
references, and constant references:
[table Required Constructor Argument Types
[[Type of `T1`] [Type of parameter to initializing constructor]]
[[T] [const T &]]
[[T &] [T &]]
[[const T &] [const T &]]
]
A little familiarity with the type traits classes allows us to construct a
single mapping that allows us to determine the type of parameter from the
type of the contained class. The type traits classes provide a
transformation __add_reference, which adds a reference to its type,
unless it is already a reference.
[table Using add_reference to synthesize the correct constructor type
[[Type of `T1`] [Type of `const T1`] [Type of `add_reference::type`]]
[[T] [const T] [const T &]]
[[T &] [T & \[8\]] [T &]]
[[const T &] [const T &] [const T &]]
]
This allows us to build a primary template definition for `pair` that can
contain non-reference types, reference types, and constant reference types:
template
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(boost::__add_reference::type nfirst,
boost::__add_reference::type nsecond)
:first(nfirst), second(nsecond) { }
};
Add back in the standard comparison operators, default constructor,
and template copy constructor (which are all the same), and you have a
`std::pair` that can hold reference types!
This same extension could have been done using partial template specialization
of `pair`, but to specialize `pair` in this way would require three partial
specializations, plus the primary template. Type traits allows us to
define a single primary template that adjusts itself auto-magically to
any of these partial specializations, instead of a brute-force partial
specialization approach. Using type traits in this fashion allows
programmers to delegate partial specialization to the type traits classes,
resulting in code that is easier to maintain and easier to understand.
[h4 Conclusion]
We hope that in this article we have been able to give you some idea of
what type-traits are all about. A more complete listing of the available
classes are in the boost documentation, along with further examples using
type traits. Templates have enabled C++ uses to take the advantage of the
code reuse that generic programming brings; hopefully this article has
shown that generic programming does not have to sink to the lowest common
denominator, and that templates can be optimal as well as generic.
[h4 Acknowledgements]
The authors would like to thank Beman Dawes and Howard Hinnant for their
helpful comments when preparing this article.
[h4 References]
# Nathan C. Myers, C++ Report, June 1995.
# The type traits library is based upon contributions by Steve Cleary, Beman Dawes, Howard Hinnant and John Maddock: it can be found at www.boost.org.
# A scalar type is an arithmetic type (i.e. a built-in integer or floating point type), an enumeration type, a pointer, a pointer to member, or a const- or volatile-qualified version of one of these types.
# This quote is from Donald Knuth, ACM Computing Surveys, December 1974, pg 268.
# The test code is available as part of the boost utility library (see algo_opt_examples.cpp), the code was compiled with gcc 2.95 with all optimisations turned on, tests were conducted on a 400MHz Pentium II machine running Microsoft Windows 98.
# John Maddock and Howard Hinnant have submitted a "compressed_pair" library to Boost, which uses a technique similar to the one described here to hold references. Their pair also uses type traits to determine if any of the types are empty, and will derive instead of contain to conserve space -- hence the name "compressed".
# This is actually an issue with the C++ Core Language Working Group (issue #106), submitted by Bjarne Stroustrup. The tentative resolution is to allow a "reference to a reference to T" to mean the same thing as a "reference to T", but only in template instantiation, in a method similar to multiple cv-qualifiers.
# For those of you who are wondering why this shouldn't be const-qualified, remember that references are always implicitly constant (for example, you can't re-assign a reference). Remember also that "const T &" is something completely different. For this reason, cv-qualifiers on template type arguments that are references are ignored.
[endsect]
[section:category Type Traits by Category]
[section:value_traits Type Traits that Describe the Properties of a Type]
These traits are all /value traits/, which is to say the traits classes all
inherit from __integral_constant, and are used to access some numerical
property of a type. Often this is a simple true or false Boolean value,
but in a few cases may be some other integer value (for example when dealing
with type alignments, or array bounds: see `__alignment_of`, `__rank` and `__extent`).
[section:primary Categorizing a Type]
These traits identify what "kind" of type some type `T` is. These are split into
two groups: primary traits which are all mutually exclusive, and composite traits
that are compositions of one or more primary traits.
For any given type, exactly one primary type trait will inherit from
__true_type, and all the others will inherit from __false_type, in other
words these traits are mutually exclusive.
This means that `__is_integral::value` and `__is_floating_point::value`
will only ever be true for built-in types; if you want to check for a
user-defined class type that behaves "as if" it is an integral or floating point type,
then use the `std::numeric_limits template` instead.
[*Synopsis:]
template
struct __is_array;
template
struct __is_class;
template
struct __is_enum;
template
struct __is_floating_point;
template
struct __is_function;
template
struct __is_integral;
template
struct __is_member_function_pointer;
template
struct __is_member_object_pointer;
template
struct __is_pointer;
template
struct __is_reference;
template
struct __is_union;
template
struct __is_void;
The following traits are made up of the union of one or more type
categorizations. A type may belong to more than one of these categories,
in addition to one of the primary categories.
template
struct __is_arithmetic;
template
struct __is_compound;
template
struct __is_fundamental;
template
struct __is_member_pointer;
template
struct __is_object;
template
struct __is_scalar;
[endsect]
[section:properties General Type Properties]
The following templates describe the general properties of a type.
[*Synopsis:]
template
struct __alignment_of;
template
struct __has_nothrow_assign;
template
struct __has_nothrow_constructor;
template
struct __has_nothrow_copy;
template
struct __has_trivial_assign;
template
struct __has_trivial_constructor;
template
struct __has_trivial_copy;
template
struct __has_trivial_destructor;
template
struct __has_virtual_destructor;
template
struct __is_abstract;
template
struct __is_const;
template
struct __is_empty;
template
struct __is_stateless;
template
struct __is_pod;
template
struct __is_polymorphic;
template
struct __is_volatile;
template
struct __extent;
template
struct __rank;
[endsect]
[section:relate Relationships Between Two Types]
These templates determine the whether there is a relationship
between two types:
[*Synopsis:]
template
struct __is_base_of;
template
struct __is_convertible;
template
struct __is_same;
[endsect]
[endsect]
[section:transform Type Traits that Transform One Type to Another]
The following templates transform one type to another,
based upon some well-defined rule.
Each template has a single member called `type` that is the
result of applying the transformation to the template argument `T`.
[*Synopsis:]
template
struct __add_const;
template
struct __add_cv;
template
struct __add_pointer;
template
struct __add_reference;
template
struct __add_volatile;
template
struct __remove_all_extents;
template
struct __remove_const;
template
struct __remove_cv;
template
struct __remove_extent;
template
struct __remove_pointer;
template
struct __remove_reference;
template
struct __remove_volatile;
[h4 Broken Compiler Workarounds:]
For all of these templates support for partial specialization of class templates is
required to correctly implement the transformation.
On the other hand, practice shows that many of the templates from this
category are very useful, and often essential for implementing some
generic libraries. Lack of these templates is often one of the major
limiting factors in porting those libraries to compilers that do not yet
support this language feature. As some of these compilers are going to be
around for a while, and at least one of them is very wide-spread,
it was decided that the library should provide workarounds where possible.
The basic idea behind the workaround is to manually define full
specializations of all type transformation templates for all fundamental types,
and all their 1st and 2nd rank cv-[un]qualified derivative pointer types, and to
provide a user-level macro that will define all the explicit specializations needed
for any user-defined type T.
The first part guarantees the successful compilation of something like this:
BOOST_STATIC_ASSERT((is_same::type>::value));
BOOST_STATIC_ASSERT((is_same::type>::value));
BOOST_STATIC_ASSERT((is_same::type>::value));
BOOST_STATIC_ASSERT((is_same::type>::value));
BOOST_STATIC_ASSERT((is_same::type>::value));
BOOST_STATIC_ASSERT((is_same::type>::value));
...
BOOST_STATIC_ASSERT((is_same::type>::value));
and the second part provides the library's users with a mechanism to make the
above code work not only for `char`, `int` or other built-in type,
but for their own types as well:
namespace myspace{
struct MyClass {};
}
// declare this at global scope:
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(myspace::MyClass)
// transformations on myspace::MyClass now work:
BOOST_STATIC_ASSERT((is_same::type>::value));
BOOST_STATIC_ASSERT((is_same::type>::value));
// etc.
Note that the macro BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION evaluates
to nothing on those compilers that *do* support partial specialization.
[endsect]
[section:alignment Synthesizing Types with Specific Alignments]
Some low level memory management routines need to synthesize a POD type with
specific alignment properties. The template `__type_with_alignment` finds the smallest
type with a specified alignment, while template `__aligned_storage` creates a type
with a specific size and alignment.
[*Synopsis]
template
struct __type_with_alignment;
template
struct __aligned_storage;
[endsect]
[section:function Decomposing Function Types]
The class template __function_traits extracts information from function types
(see also __is_function). This traits class allows you to tell how many arguments
a function takes, what those argument types are, and what the return type is.
[*Synopsis]
template
struct __function_traits;
[endsect]
[endsect]
[section:user_defined User Defined Specializations]
Occationally the end user may need to provide their own specialization
for one of the type traits - typically where intrinsic compiler support
is required to implement a specific trait fully.
These specializations should derive from boost::__true_type or boost::__false_type
as appropriate:
#include
#include
#include
struct my_pod{};
struct my_union
{
char c;
int i;
};
namespace boost
{
template<>
struct __is_pod : public __true_type{};
template<>
struct __is_pod : public __true_type{};
template<>
struct __is_union : public __true_type{};
template<>
struct __is_class : public __false_type{};
}
[endsect]
[section:intrinsics Support for Compiler Intrinsics]
There are some traits that can not be implemented within the current C++ language:
to make these traits "just work" with user defined types, some kind of additional
help from the compiler is required. Currently (May 2005) MWCW 9 and Visual C++ 8
provide the necessary intrinsics, and other compilers will no doubt follow in due
course.
The Following traits classes always need compiler support to do the right thing
for all types
(but all have safe fallback positions if this support is unavailable):
* __is_union
* __is_pod
* __has_trivial_constructor
* __has_trivial_copy
* __has_trivial_assign
* __has_trivial_destructor
* __has_nothrow_constructor
* __has_nothrow_copy
* __has_nothrow_assign
* __has_virtual_destructor
The following traits classes can't be portably implemented in the C++ language,
although in practice, the implementations do in fact do the right thing on all
the compilers we know about:
* __is_empty
* __is_polymorphic
The following traits classes are dependent on one or more of the above:
* __is_class
* __is_stateless
The hooks for compiler-intrinsic support are defined in
[@../../boost/type_traits/intrinsics.hpp boost/type_traits/intrinsics.hpp], adding support for new compilers is simply
a matter of defining one of more of the following macros:
[table Macros for Compiler Intrinsics
[[BOOST_IS_UNION(T)][Should evaluate to true if T is a union type]]
[[BOOST_IS_POD(T)][Should evaluate to true if T is a POD type]]
[[BOOST_IS_EMPTY(T)][Should evaluate to true if T is an empty struct or union]]
[[BOOST_HAS_TRIVIAL_CONSTRUCTOR(T)][Should evaluate to true if the default constructor for T is trivial (i.e. has no effect)]]
[[BOOST_HAS_TRIVIAL_COPY(T)][Should evaluate to true if T has a trivial copy constructor (and can therefore be replaced by a call to memcpy)]]
[[BOOST_HAS_TRIVIAL_ASSIGN(T)][Should evaluate to true if T has a trivial assignment operator (and can therefore be replaced by a call to memcpy)]]
[[BOOST_HAS_TRIVIAL_DESTRUCTOR(T)][Should evaluate to true if T has a trivial destructor (i.e. ~T() has no effect)]]
[[BOOST_HAS_NOTHROW_CONSTRUCTOR(T)][Should evaluate to true if `T x;` can not throw]]
[[BOOST_HAS_NOTHROW_COPY(T)][Should evaluate to true if `T(t)` can not throw]]
[[BOOST_HAS_NOTHROW_ASSIGN(T)][Should evaluate to true if `T t, u; t = u` can not throw]]
[[BOOST_HAS_VIRTUAL_DESTRUCTOR(T)][Should evaluate to true T has a virtual destructor]]
]
[endsect]
[section:mpl MPL Interoperability]
All the value based traits in this library conform to MPL's requirements
for an [@../../libs/mpl/doc/refmanual/integral-constant.html Integral Constant type]: that includes a number of rather intrusive
workarounds for broken compilers.
Purely as an implementation detail, this
means that `__true_type` inherits from [@../../libs/mpl/doc/refmanual/bool.html `boost::mpl::true_`], `__false_type` inherits
from [@../../libs/mpl/doc/refmanual/bool.html `boost::mpl::false_`], and `__integral_constant` inherits from
[@../../libs/mpl/doc/refmanual/integral-c.html `boost::mpl::integral_c`] (provided `T` is not `bool`)
[endsect]
[section:examples Examples]
[section:copy An Optimized Version of std::copy]
Demonstrates a version of `std::copy` that uses `__has_trivial_assign` to
determine whether to use `memcpy` to optimise the copy operation
(see [@../../libs/type_traits/examples/copy_example.cpp copy_example.cpp]):
//
// opt::copy
// same semantics as std::copy
// calls memcpy where appropriate.
//
namespace detail{
template
I2 copy_imp(I1 first, I1 last, I2 out, const boost::__integral_constant&)
{
while(first != last)
{
*out = *first;
++out;
++first;
}
return out;
}
template
T* copy_imp(const T* first, const T* last, T* out, const boost::__true_type&)
{
memcpy(out, first, (last-first)*sizeof(T));
return out+(last-first);
}
}
template
inline I2 copy(I1 first, I1 last, I2 out)
{
//
// We can copy with memcpy if T has a trivial assignment operator,
// and if the iterator arguments are actually pointers (this last
// requirement we detect with overload resolution):
//
typedef typename std::iterator_traits::value_type value_type;
return detail::copy_imp(first, last, out, boost::__has_trivial_assign());
}
[endsect]
[section:fill An Optimised Version of std::fill]
Demonstrates a version of `std::fill` that uses `__has_trivial_assign` to
determine whether to use `memset` to optimise the fill operation
(see [@../../libs/type_traits/examples/fill_example.cpp fill_example.cpp]):
//
// fill
// same as std::fill, but uses memset where appropriate
//
namespace detail{
template
void do_fill(I first, I last, const T& val, const boost::__integral_constant&)
{
while(first != last)
{
*first = val;
++first;
}
}
template
void do_fill(T* first, T* last, const T& val, const boost::__true_type&)
{
std::memset(first, val, last-first);
}
}
template
inline void fill(I first, I last, const T& val)
{
//
// We can do an optimised fill if T has a trivial assignment
// operator and if it's size is one:
//
typedef boost::__integral_constant::value && (sizeof(T) == 1)> truth_type;
detail::do_fill(first, last, val, truth_type());
}
[endsect]
[section:destruct An Example that Omits Destructor Calls For Types with Trivial Destructors]
Demonstrates a simple algorithm that uses `__has_trivial_destruct` to
determine whether to destructors need to be called
(see [@../../libs/type_traits/examples/trivial_destructor_example.cpp trivial_destructor_example.cpp]):
//
// algorithm destroy_array:
// The reverse of std::unitialized_copy, takes a block of
// initialized memory and calls destructors on all objects therein.
//
namespace detail{
template
void do_destroy_array(T* first, T* last, const boost::__false_type&)
{
while(first != last)
{
first->~T();
++first;
}
}
template
inline void do_destroy_array(T* first, T* last, const boost::__true_type&)
{
}
} // namespace detail
template
inline void destroy_array(T* p1, T* p2)
{
detail::do_destroy_array(p1, p2, ::boost::__has_trivial_destructor());
}
[endsect]
[section:iter An improved Version of std::iter_swap]
Demonstrates a version of `std::iter_swap` that use type traits to
determine whether an it's arguments are proxying iterators or not,
if they're not then it just does a `std::swap` of it's dereferenced
arguments (the
same as `std::iter_swap` does), however if they are proxying iterators
then takes special care over the swap to ensure that the algorithm
works correctly for both proxying iterators, and even iterators of
different types
(see [@../../libs/type_traits/examples/iter_swap_example.cpp iter_swap_example.cpp]):
//
// iter_swap:
// tests whether iterator is a proxying iterator or not, and
// uses optimal form accordingly:
//
namespace detail{
template
static void do_swap(I one, I two, const boost::__false_type&)
{
typedef typename std::iterator_traits::value_type v_t;
v_t v = *one;
*one = *two;
*two = v;
}
template
static void do_swap(I one, I two, const boost::__true_type&)
{
using std::swap;
swap(*one, *two);
}
}
template
inline void iter_swap(I1 one, I2 two)
{
//
// See is both arguments are non-proxying iterators,
// and if both iterator the same type:
//
typedef typename std::iterator_traits::reference r1_t;
typedef typename std::iterator_traits::reference r2_t;
typedef boost::__integral_constant::value
&& ::boost::__is_reference::value
&& ::boost::__is_same::value> truth_type;
detail::do_swap(one, two, truth_type());
}
[endsect]
[endsect]
[section:reference Alphabetical Reference]
[section:add_const add_const]
template
struct add_const
{
typedef __below type;
};
__type The same type as `T const` for all `T`.
__std_ref 3.9.3.
__compat If the compiler does not support partial specialization of class-templates
then this template will compile, but the member `type` will always be the same as
type `T` except where __transform_workaround have been applied.
__header ` #include ` or ` #include `
[table Examples
[ [Expression] [Result Type]]
[[`add_const::type`][`int const`]]
[[`add_const::type`] [`int&`]]
[[`add_const::type`] [`int* const`]]
[[`add_const::type`] [`int const`]]
]
[endsect]
[section:add_cv add_cv]
template
struct add_cv
{
typedef __below type;
};
__type The same type as `T const volatile` for all `T`.
__std_ref 3.9.3.
__compat If the compiler does not support partial specialization of class-templates
then this template will compile, but the member `type` will always be the same as
type `T` except where __transform_workaround have been applied.
__header ` #include ` or ` #include `
[table Examples
[ [Expression] [Result Type]]
[[`add_cv::type`][`int const volatile`]]
[[`add_cv::type`] [`int&`]]
[[`add_cv::type`] [`int* const volatile`]]
[[`add_cv::type`] [`int const volatile`]]
]
[endsect]
[section:add_pointer add_pointer]
template
struct add_pointer
{
typedef __below type;
};
__type The same type as `remove_reference::type*`.
The rationale for this template
is that it produces the same type as `TYPEOF(&t)`,
where `t` is an object of type `T`.
__std_ref 8.3.1.
__compat If the compiler does not support partial specialization of class-templates
then this template will compile, but the member `type` will always be the same as
type `T` except where __transform_workaround have been applied.
__header ` #include ` or ` #include `
[table Examples
[ [Expression] [Result Type]]
[[`add_pointer::type`][`int*`]]
[[`add_pointer::type`] [`int const*`]]
[[`add_pointer::type`] [`int**`]]
[[`add_pointer::type`] [`int**`]]
]
[endsect]
[section:add_reference add_reference]
template
struct add_reference
{
typedef __below type;
};
__type If `T` is not a reference type then `T&`, otherwise `T`.
__std_ref 8.3.2.
__compat If the compiler does not support partial specialization of class-templates
then this template will compile, but the member `type` will always be the same as
type `T` except where __transform_workaround have been applied.
__header ` #include ` or ` #include `
[table Examples
[ [Expression] [Result Type]]
[[`add_reference::type`][`int&`]]
[[`add_reference::type`] [`int const&`]]
[[`add_reference::type`] [`int*&`]]
[[`add_reference::type`] [`int*&`]]
]
[endsect]
[section:add_volatile add_volatile]
template
struct add_volatile
{
typedef __below type;
};
__type The same type as `T volatile` for all `T`.
__std_ref 3.9.3.
__compat If the compiler does not support partial specialization of class-templates
then this template will compile, but the member `type` will always be the same as
type `T` except where __transform_workaround have been applied.
__header ` #include ` or ` #include `
[table Examples
[ [Expression] [Result Type]]
[[`add_volatile::type`][`int volatile`]]
[[`add_volatile::type`] [`int&`]]
[[`add_volatile::type`] [`int* volatile`]]
[[`add_volatile::type`] [`int const volatile`]]
]
[endsect]
[section:aligned_storage aligned_storage]
template
struct aligned_storage
{
typedef __below type;
};
__type a built-in or POD type with size `Size` and an alignment
that is a multiple of `Align`.
__header ` #include ` or ` #include `
[endsect]
[section:alignment_of alignment_of]
template
struct alignment_of : public __integral_constant {};
__inherit Class template alignment_of inherits from
`__integral_constant`, where `ALIGNOF(T)` is the
alignment of type T.
['Note: strictly speaking you should only rely on
the value of `ALIGNOF(T)` being a multiple of the true alignment of T, although
in practice it does compute the correct value in all the cases we know about.]
__header ` #include ` or ` #include `
__examples
[:`alignment_of` inherits from `__integral_constant`.]
[:`alignment_of::type` is the type `__integral_constant`.]
[:`alignment_of::value` is an integral constant
expression with value `ALIGNOF(double)`.]
[:`alignment_of::value_type` is the type `std::size_t`.]
[endsect]
[section:extent extent]
template
struct extent : public __integral_constant {};
__inherit Class template extent inherits from `__integral_constant`,
where `EXTENT(T,N)` is the number of elements in the N'th array dimention of type `T`.
If `T` is not an array type, or if `N > __rank::value`, or if the N'th array bound
is incomplete, then `EXTENT(T,N)` is zero.
__header ` #include ` or ` #include `
__examples
[:`extent` inherits from `__integral_constant`.]
[:`extent::type` is the type `__integral_constant`.]
[:`extent::value` is an integral constant
expression that evaluates to /4/.]
[:`extent::value` is an integral constant
expression that evaluates to /0/.]
[:`extent::value` is an integral constant
expression that evaluates to /2/.]
[:`extent::value` is an integral constant
expression that evaluates to /0/.]
[:`extent::value_type` is the type `std::size_t`.]
[endsect]
[section:function_traits function_traits]
[def __argN '''argN_type''']
template
struct function_traits
{
static const std::size_t arity = __below;
typedef __below result_type;
typedef __below __argN;
};
The class template function_traits will only compile if:
* The compiler supports partial specialization of class templates.
* The template argument `T` is a /function type/, note that this ['[*is not]]
the same thing as a /pointer to a function/.
[table Function Traits Members
[[Member] [Description]]
[[`function_traits::arity`]
[An integral constant expression that gives the number of arguments accepted by the function type `F`.]]
[[`function_traits::result_type`]
[The type returned by function type `F`.]]
[[`function_traits::__argN`]
[The '''Nth''' argument type of function type `F`, where `1 <= N <= arity` of `F`.]]
]
[table Examples
[[Expression] [Result]]
[[`function_traits::arity`] [An integral constant expression that has the value 0.]]
[[`function_traits::arity`] [An integral constant expression that has the value 1.]]
[[`function_traits::arity`] [An integral constant expression that has the value 4.]]
[[`function_traits::result_type`] [The type `void`.]]
[[`function_traits::result_type`] [The type `long`.]]
[[`function_traits::arg1_type`] [The type `int`.]]
[[`function_traits::arg4_type`] [The type `void*`.]]
[[`function_traits::arg5_type`] [A compiler error: there is no `arg4_type` since there are only three arguments.]]
[[`function_traits::arity`] [A compiler error: argument type is a /function pointer/, and not a /function type/.]]
]
[endsect]
[section:has_nothrow_assign has_nothrow_assign]
template
struct has_nothrow_assign : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a non-throwing assignment-operator
then inherits from __true_type, otherwise inherits from __false_type. Type `T`
must be a complete type.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
`has_nothrow_assign` will never report that a class or struct has a
non-throwing assignment-operator; this is always safe, if possibly sub-optimal.
Currently (May 2005) only Visual C++ 8 has the necessary compiler support to ensure that this
trait "just works".
__header ` #include ` or ` #include `
[endsect]
[section:has_nothrow_constructor has_nothrow_constructor]
template
struct has_nothrow_constructor : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a non-throwing default-constructor
then inherits from __true_type, otherwise inherits from __false_type. Type `T`
must be a complete type.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
`has_nothrow_constructor` will never report that a class or struct has a
non-throwing default-constructor; this is always safe, if possibly sub-optimal.
Currently (May 2005) only Visual C++ 8 has the necessary compiler __intrinsics to ensure that this
trait "just works".
__header ` #include ` or ` #include `
[endsect]
[section:has_nothrow_copy has_nothrow_copy]
template
struct has_nothrow_copy : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a non-throwing copy-constructor
then inherits from __true_type, otherwise inherits from __false_type. Type `T`
must be a complete type.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
`has_nothrow_copy` will never report that a class or struct has a
non-throwing copy-constructor; this is always safe, if possibly sub-optimal.
Currently (May 2005) only Visual C++ 8 has the necessary compiler __intrinsics to ensure that this
trait "just works".
__header ` #include ` or ` #include `
[endsect]
[section:has_trivial_assign has_trivial_assign]
template
struct has_trivial_assign : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a trivial assignment-operator
then inherits from __true_type, otherwise inherits from __false_type.
If a type has a trivial assignment-operator then the operator has the same effect
as copying the bits of one object to the other:
calls to the operator can be safely replaced with a call to `memcpy`.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
has_trivial_assign will never report that a user-defined class or struct has a
trivial constructor; this is always safe, if possibly sub-optimal. Currently
(May 2005) only MWCW 9 and Visual C++ 8 have the necessary compiler __intrinsics to detect
user-defined classes with trivial constructors.
__std_ref 12.8p11.
__header ` #include ` or ` #include `
__examples
[:`has_trivial_assign` inherits from `__true_type`.]
[:`has_trivial_assign::type` is the type `__true_type`.]
[:`has_trivial_assign::value` is an integral constant
expression that evaluates to /true/.]
[:`has_trivial_assign::value` is an integral constant
expression that evaluates to /false/.]
[:`has_trivial_assign::value_type` is the type `bool`.]
[endsect]
[section:has_trivial_constructor has_trivial_constructor]
template
struct has_trivial_constructor : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a trivial default-constructor
then inherits from __true_type, otherwise inherits from __false_type.
If a type has a trivial default-constructor then the constructor have no effect:
calls to the constructor can be safely omitted. Note that using meta-programming
to omit a call to a single trivial-constructor call is of no benefit whatsoever.
However, if loops and/or exception handling code can also be omitted, then some
benefit in terms of code size and speed can be obtained.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
has_trivial_constructor will never report that a user-defined class or struct has a
trivial constructor; this is always safe, if possibly sub-optimal. Currently
(May 2005) only MWCW 9 and Visual C++ 8 have the necessary compiler __intrinsics to detect
user-defined classes with trivial constructors.
__std_ref 12.1p6.
__header ` #include ` or ` #include `
__examples
[:`has_trivial_constructor` inherits from `__true_type`.]
[:`has_trivial_constructor::type` is the type `__true_type`.]
[:`has_trivial_constructor::value` is an integral constant
expression that evaluates to /true/.]
[:`has_trivial_constructor::value` is an integral constant
expression that evaluates to /false/.]
[:`has_trivial_constructor::value_type` is the type `bool`.]
[endsect]
[section:has_trivial_copy has_trivial_copy]
template
struct has_trivial_copy : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a trivial copy-constructor
then inherits from __true_type, otherwise inherits from __false_type.
If a type has a trivial copy-constructor then the constructor has the same effect
as copying the bits of one object to the other:
calls to the constructor can be safely replaced with a call to `memcpy`.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
has_trivial_copy will never report that a user-defined class or struct has a
trivial constructor; this is always safe, if possibly sub-optimal. Currently
(May 2005) only MWCW 9 and Visual C++ 8 have the necessary compiler __intrinsics to detect
user-defined classes with trivial constructors.
__std_ref 12.8p6.
__header ` #include ` or ` #include `
__examples
[:`has_trivial_copy` inherits from `__true_type`.]
[:`has_trivial_copy::type` is the type `__true_type`.]
[:`has_trivial_copy::value` is an integral constant
expression that evaluates to /true/.]
[:`has_trivial_copy::value` is an integral constant
expression that evaluates to /false/.]
[:`has_trivial_copy::value_type` is the type `bool`.]
[endsect]
[section:has_trivial_destructor has_trivial_destructor]
template
struct has_trivial_destructor : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a trivial destructor
then inherits from __true_type, otherwise inherits from __false_type.
If a type has a trivial destructor then the destructor has no effect:
calls to the destructor can be safely omitted. Note that using meta-programming
to omit a call to a single trivial-constructor call is of no benefit whatsoever.
However, if loops and/or exception handling code can also be omitted, then some
benefit in terms of code size and speed can be obtained.
__compat If the compiler does not support partial-specialization of class
templates, then this template can not be used with function types.
Without some (as yet unspecified) help from the compiler,
has_trivial_destructor will never report that a user-defined class or struct has a
trivial destructor; this is always safe, if possibly sub-optimal. Currently
(May 2005) only MWCW 9 and Visual C++ 8 have the necessary compiler __intrinsics to detect
user-defined classes with trivial constructors.
__std_ref 12.4p3.
__header ` #include ` or ` #include `
__examples
[:`has_trivial_destructor` inherits from `__true_type`.]
[:`has_trivial_destructor::type` is the type `__true_type`.]
[:`has_trivial_destructor::value` is an integral constant
expression that evaluates to /true/.]
[:`has_trivial_destructor::value` is an integral constant
expression that evaluates to /false/.]
[:`has_trivial_destructor::value_type` is the type `bool`.]
[endsect]
[section:has_virtual_destructor has_virtual_destructor]
template
struct has_virtual_destructor : public __tof {};
__inherit If T is a (possibly cv-qualified) type with a virtual destructor
then inherits from __true_type, otherwise inherits from __false_type.
__compat This trait is provided for completeness, since it's part of the
Technical Report on C++ Library Extensions. However, there is currently no
way to portably implement this trait. The default version provided
always inherits from __false_type, and has to be explicitly specialized for
types with virtual destructors unless the compiler used has compiler __intrinsics
that enable the trait to do the right thing: currently (May 2005) only Visual C++
8 has the necessary __intrinsics.
__std_ref 12.4.
__header ` #include