diff --git a/cxx_type_traits.htm b/cxx_type_traits.htm index 59f188d..28f1073 100644 --- a/cxx_type_traits.htm +++ b/cxx_type_traits.htm @@ -1,590 +1,15 @@ + - -
- - - -by John Maddock and Steve Cleary
- -This is the draft version of an article -that appeared in the October 2000 issue of 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 minimise the amount of code that has to -differ from one type to another, and maximise 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 realised 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 specialisations of char_traits will use the most -appropriate method available to them.
- -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[1]. In the Boost type-traits library, we[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 has a single member value, -a compile-time constant that is true if the type has the -specified property, and false otherwise. As we will show, these -classes can be used in generic programming to determine the -properties of a given type and introduce optimisations 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.
- -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 flavour for how some of the classes are implemented. -Beginning with possibly the simplest class in the library, is_void<T> -has a member value that is true only if T is void.
- -template <typename T> -struct is_void -{ static const bool value = false; }; - -template <> -struct is_void<void> -{ static const bool value = true; };- -
Here we define a primary version of the template class is_void, and provide a full-specialisation -when T is void. While full specialisation of a template class is -an important technique, sometimes we need a solution that is -halfway between a fully generic solution, and a full -specialisation. This is exactly the situation for which the -standards committee defined partial template-class specialisation. -As an example, consider the class boost::is_pointer<T>: -here we needed a primary version that handles all the cases where -T is not a pointer, and a partial specialisation to handle all -the cases where T is a pointer:
- -template <typename T> -struct is_pointer -{ static const bool value = false; }; - -template <typename T> -struct is_pointer<T*> -{ static const bool value = true; };- -
The syntax for partial specialisation is somewhat arcane and -could easily occupy an article in its own right; like full -specialisation, in order to write a partial specialisation for a -class, you must first declare the primary template. The partial -specialisation contains an extra < > after the class -name that contains the partial specialisation parameters; these -define the types that will bind to that partial specialisation -rather than the default template. The rules for what can appear -in a partial specialisation 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 specialisation of the form:
- -template <typename T> -class c{ /*details*/ }; - -template <typename T> - -class c<U>{ /*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 specialisation consider -the class remove_bounds<T>. 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 <typename T> -struct remove_bounds -{ typedef T type; }; - -template <typename T, std::size_t N> -struct remove_bounds<T[N]> -{ typedef T type; };- -
The aim of remove_bounds is this: imagine a generic algorithm
-that is passed an array type as a template parameter, remove_bounds provides a means
-of determining the underlying type of the array. For example remove_bounds<int[4][5]>::type
-would evaluate to the type int[5]
. This example also
-shows that the number of template parameters in a partial
-specialisation 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.
As an example of how the type traits classes can be used, -consider the standard library algorithm copy:
- -template<typename Iter1, typename Iter2> -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:
- -By trivial assignment operator we mean that the type is either -a scalar type[3] or:
- -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<T>::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 optimised version of copy that uses memcpy where appropriate is -given in listing 1. The code begins by defining a template class copier, -that takes a single Boolean template parameter, and has a static -template member function do_copy -which performs the generic version of copy -(in other words the "slow but safe version"). Following -that there is a specialisation for copier<true>: -again this defines a static template member function do_copy, but this version uses -memcpy to perform an "optimised" copy.
- -In order to complete the implementation, what we need now is a
-version of copy, that calls copier<true>::do_copy
-if it is safe to use memcpy,
-and otherwise calls copier<false>::do_copy
to
-do a "generic" copy. This is what the version in
-listing 1 does. To understand how the code works look at the code
-for copy and consider
-first the two typedefs v1_t and v2_t. These use std::iterator_traits<Iter1>::value_type
-to determine what type the two iterators point to, and then feed
-the result into another type-traits class remove_cv that
-removes the top-level const-volatile-qualifiers: this will allow
-copy to compare the two types without regard to const- or
-volatile-qualifiers. Next, copy
-declares an enumerated value can_opt that will become the
-template parameter to copier - declaring this here as a constant
-is really just a convenience - the value could be passed directly
-to class copier. The
-value of can_opt is computed by verifying that all of the
-following are true:
Finally we can use the value of can_opt as the template -argument to copier - this version of copy will now adapt to -whatever parameters are passed to it, if its possible to use memcpy, then it will do so, -otherwise it will use a generic copy.
- -It has often been repeated in these columns that "premature -optimisation is the root of all evil" [4]. So the question -must be asked: was our optimisation premature? To put this in -perspective the timings for our version of copy compared a -conventional generic copy[5] are shown in table 1.
- -Clearly the optimisation 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 optimisation rule:
- -Version - |
- T - |
- Time - |
-
"Optimised" copy | -char | -0.99 | -
Conventional copy | -char | -8.07 | -
"Optimised" copy | -int | -2.52 | -
Conventional copy | -int | -8.02 | -
- -
The optimised copy example shows how type traits may be used -to perform optimisation 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 [6].
- -First, let us examine the definition of "std::pair", -omitting the comparision operators, default constructor, and -template copy constructor for simplicity:
- -template <typename T1, typename T2> -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 [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:
- -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.
- -Type of "T1" | -Type of "const T1" | -Type of "add_reference<const - T1>::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 <typename T1, typename T2> -struct pair -{ - typedef T1 first_type; - typedef T2 second_type; - - T1 first; - T2 second; - - pair(boost::add_reference<const T1>::type nfirst, - boost::add_reference<const T2>::type nsecond) - :first(nfirst), second(nsecond) { } -};- -
Add back in the standard comparision 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.
- -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.
- -The authors would like to thank Beman Dawes and Howard Hinnant -for their helpful comments when preparing this article.
- -namespace detail{ - -template <bool b> -struct copier -{ - template<typename I1, typename I2> - static I2 do_copy(I1 first, - I1 last, I2 out); -}; - -template <bool b> -template<typename I1, typename I2> -I2 copier<b>::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; - - enum{ can_opt = - 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 - }; - - return detail::copier<can_opt>:: - do_copy(first, last, out); -}- -
© Copyright John Maddock and Steve Cleary, 2000
- + + + + + Automatic redirection failed, please go to + ../../doc/html/boost_typetraits/background.html + or view the online version at + http://www.boost.org/regression-logs/cs-win32_metacomm/doc/html/boost_typetraits/background.html + + + + diff --git a/index.html b/index.html index 989eeb2..1180f8b 100644 --- a/index.html +++ b/index.html @@ -1,1230 +1,15 @@ + - -Introduction -Primary Type Categorisation -Secondary Type Categorisation -Type Properties -Relationships Between Types -Transformations Between Types -Synthesizing Types -Function Traits -Type traits headers-
User defined specializations -Example Code
The contents of <boost/type_traits.hpp> are declared in namespace boost.
-The file <boost/type_traits.hpp> - defines three kinds of type trait:
-If you are new to this library then the accompanying - article provides the background information and motivation.
-All of the integral expressions in this library are - integral constant expressions, these can sometimes cause - compiler problems in use, so there is a related set of - coding guidelines to help you write portable code using this library.
-The following type traits templates identify which type category the type
- belongs to. For any given type, exactly one of the following expressions will
- evaluate to true. Note that this means that is_integral<T>::value
- and is_floating_point<T>::value
will only every be true for
- built-in types; if you want to check for a user-defined type that may behave
- "as if" it is an integral or floating point type, then use the
- std::numeric_limits template instead.
- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- | ::boost::is_void<T>::value |
- Evaluates to true only if T is a - cv-qualified void type. | -3.9.1p9 - |
- - | - |
- | ::boost::is_integral<T>::value |
- Evaluates to true only if T is an - cv-qualified integral type. | -3.9.1p7 - |
- - | - |
- | ::boost::is_floating_point<T>::value |
- Evaluates to true only if T is a - cv-qualified floating point type. | -3.9.1p8 - |
- - | - |
- | ::boost::is_pointer<T>::value |
- Evaluates to true only if T is - cv-qualified pointer type (includes function pointers, but excludes pointers to - members). | -3.9.2p2 -8.3.1 - |
- - | - |
- | ::boost::is_reference<T>::value |
- Evaluates to true only if T is a - reference type. | -3.9.2 -8.3.2 - |
- If the compiler does not support - partial-specialization of class templates, then this template may report the - wrong result for function types. | -- |
- | ::boost::is_member_pointer<T>::value |
- Evaluates to true only if T is a - cv-qualified pointer to a data-member or member-function. | -3.9.2 -8.3.3 - |
- - | - |
- | ::boost::is_array<T>::value |
- Evaluates to true only if T is an - array type. | -3.9.2 -8.3.4 - |
- If the compiler does not support - partial-specialization of class templates, then this template can give the - wrong result with function types. | -- |
- | ::boost::is_union<T>::value |
- Evaluates to true only if T is of - union type. Currently requires some kind of compiler support, otherwise unions - are identified as classes. | -3.9.2 -9.5 - |
- Without (some as yet unspecified) - help from the compiler, we cannot distinguish between union and class types, as - a result this expression will never evaluate to true. | -- |
- | ::boost::is_class<T>::value |
- Evaluates to true only if T is of - class/struct type. | -3.9.2 -9.2 - |
- Without (some as yet unspecified) - help from the compiler, we cannot distinguish between union and class types, as - a result this expression will erroneously evaluate to true for union types. | -- |
- | ::boost::is_enum<T>::value |
- Evaluates to true only if T is of - enum type. | -3.9.2 -7.2 - |
- Requires a correctly functioning - is_convertible template; this means that is_enum is currently broken under - Borland C++ Builder 5, and for the Metrowerks compiler prior to version 8, - other compilers should handle this template just fine. | -- |
- | ::boost::is_function<T>::value |
- Evaluates to true only if T is a function type - (note not a reference or pointer to function). | -3.9.2p1 -8.3.5 - |
- If the compiler does not support - partial-specialization of class templates, then this template does not compile - for reference types. | -- |
-
The following type categories are made up of the union of one or more primary - type categorisations. A type may belong to more than one of these categories, - in addition to one of the primary categories.
-- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- | ::boost::is_arithmetic<T>::value |
- Evaluates to true only if T is a - cv-qualified arithmetic type. That is either an integral or floating point - type. | -3.9.1p8 - |
- - | - |
- | ::boost::is_fundamental<T>::value |
- Evaluates to true only if T is an - cv-qualified fundamental type. That is either an integral, a floating point, or - a void type. | -3.9.1 - |
- - | - |
- | ::boost::is_object<T>::value |
- Evaluates to true only if T is a - cv-qualified object type. That is not a function, reference, or void type. | -3.9p9 - |
- - | - |
- | ::boost::is_scalar<T>::value |
- Evaluates to true only if T is - cv-qualified scalar type. That is an arithmetic, enumeration, pointer or a - pointer to member type. | -3.9p10 - |
- If the compiler does not support - partial-specialization of class templates, then this template can not be used - with function types. | -- |
- | ::boost::is_compound<T>::value |
- - Evaluates to true only if T is a compound type. (Any type that is not a - fundamental type is a compound type). | -3.9.2 - |
- - | - |
- | ::boost::is_member_function_pointer<T>::value |
- Evaluates to true only if T is a pointer to a member - function (and not a pointer to a member object). This template splits - is_member_pointer into two sub-categories. | -3.9.2 -8.3.3 - |
- - | - |
- | ::boost::is_member_object_pointer<T>::value |
- Evaluates to true only if T is a pointer to a member - object(and not a pointer to a member function). This template splits - is_member_pointer into two sub-categories. | -
- 3.9.2 -8.3.3 - |
- - | - |
-
The following templates identify the properties that a type has.
-- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- | ::boost::alignment_of<T>::value |
-
- Identifies the alignment requirements of T. Actually returns a value that is - only guaranteed to be a multiple of the actual alignment requirements of T. -T must be a complete type. - |
- - | - | - |
- | ::boost::rank<T>::value |
- The number of array dimentions in type T. - Zero if T is not an array type. | -- | Requires partial specialisation of class - templates. | -- |
- | ::boost::extent<T, std::size_t N =
- 0>::value |
- The number of elements in the N'th array bound - of T. If T has fewer than N bounds, or if the N'th array bound is - incomplete, then zero. | -- | Requires partial specialisation of class - templates. | -- |
- | ::boost::is_empty<T>::value |
-
- True if T is an empty struct or class. If the compiler implements the "zero - sized empty base classes" optimisation, then is_empty will correctly guess - whether T is empty. Relies upon is_class to determine whether T is a class - type. - -T must be a complete type. - |
- 10p5 - |
- Relies on the compiler - implementing zero sized empty base classes in order to detect empty classes. - -Can not be used with incomplete types. -Can not be used with union types, until is_union can be made to - work. -If the compiler does not support partial-specialization of class - templates, then this template can not be used with abstract types. - |
- - |
- | ::boost::is_const<T>::value |
- Evaluates to true only if T is top-level - const-qualified. | -3.9.3 - |
- - | - |
- | ::boost::is_volatile<T>::value |
- Evaluates to true only if T is - volatile-qualified. | -3.9.3 - |
- - | - |
- | ::boost::is_abstract<T>::value |
- Evaluates true only if T is abstract class. | -10.3 | -
- Compiler must support DR337 (as Jan 2004: GCC 3.4, VC++ 7.1, Intel C++ 7, and - Comeau 4.3.2). -Otherwise produces the same value as is_polymorphic<T>::value; this is - the "safe fallback position" for which polymorphic types are - always regarded as potentially abstract. -The macro BOOST_NO_IS_ABSTRACT is used to signify that the implemention is - buggy, users should check for this in their own code if the "safe fallback" is - not suitable for their particular use-case. - |
- - |
- | ::boost::is_polymorphic<T>::value |
- Evaluates to true only if T is a polymorphic
- type.
- T must be a complete type. - |
- 10.3 | -Requires knowledge of the compilers ABI, does - actually seem to work with the majority of compilers though. | -- |
- | ::boost::has_virtual_destructor<T>::value |
- Should evaluate to true whenever type T has a - virtual destructor: currently evaluates to false in all cases, unless - user-specialised. | -12.4 | -There is currently no way to portably implement - this trait, the default version provided always evaluates to false, and has to - be explicity specialised for types with virtual destructors. | -- |
- | ::boost::is_pod<T>::value |
- Evaluates to true only if T is a cv-qualified
- POD type.
- T must be a complete type. - |
- 3.9p10 -9p4 - |
- Without some (as yet unspecified) help from the
- compiler, is_pod will never report that a class or struct is a POD; this is
- always safe, if possibly sub-optimal. If the compiler does not support - partial-specialization of class templates, then this template can not be used - with function types. - |
- - |
- | ::boost::has_trivial_constructor<T>::value |
- True if T has a trivial default constructor. | -12.1p5 | -Without some (as yet unspecified)
- help from the compiler, If the compiler does not support partial-specialization of class templates, - then this template can not be used with function types. - |
- - |
- | ::boost::has_trivial_copy<T>::value |
- True if T has a trivial copy constructor.
- T must be a complete type. - |
- 12.8p6 | -Without some (as yet unspecified)
- help from the compiler, If the compiler does not support partial-specialization of class templates, - then this template can not be used with function types. - |
- - |
- | ::boost::has_trivial_assign<T>::value |
- True if T has a trivial assignment operator.
- T must be a complete type. - |
- 12.8p11 | -Without some (as yet unspecified)
- help from the compiler, If the compiler does not support partial-specialization of class templates, - then this template can not be used with function types. - |
- - |
- | ::boost::has_trivial_destructor<T>::value |
- True if T has a trivial destructor.
- T must be a complete type. - |
- 12.4p3 | -Without some (as yet unspecified)
- help from the compiler, If the compiler does not support partial-specialization of class templates, - then this template can not be used with function types. - |
- - |
- | ::boost::is_stateless<T>::value |
- True if T is stateless, meaning that T has no
- storage and its constructors and destructors are trivial.
- T must be a complete type. - |
- - | Without some (as yet unspecified)
- help from the compiler, Will report true only if all of the following also report true: -::boost::has_trivial_constructor<T>::value, -::boost::has_trivial_copy<T>::value, -::boost::has_trivial_destructor<T>::value, -::boost::is_class<T>::value, -::boost::is_empty<T>::value- If the compiler does not support partial-specialization of class templates, - then this template can not be used with function types. - |
- - |
- | ::boost::has_nothrow_constructor<T>::value |
- True if T has a non-throwing default
- constructor.
- T must be a complete type. - |
- - | Without some (as yet
- unspecified) help from the compiler, If the compiler does not support partial-specialization of class - templates, then this template can not be used with function types. - |
- - |
- | ::boost::has_nothrow_copy<T>::value |
- True if T has a non-throwing copy constructor.
- T must be a complete type. - |
- - | Without some (as yet
- unspecified) help from the compiler, If the compiler does not support partial-specialization of class - templates, then this template can not be used with function types. - |
- - |
- | ::boost::has_nothrow_assign<T>::value |
- True if T has a non-throwing assignment
- operator.
- T must be a complete type. - |
- - | Without some (as yet
- unspecified) help from the compiler, If the compiler does not support partial-specialization of class - templates, then this template can not be used with function types. - |
- - |
-
The following templates determine the whether there is a relationship between - two types:
-- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- |
- |
- Evaluates to true if T - and U are the same type. - |
- - | If the compiler does not support - partial-specialization of class templates, then this template can not be used - with abstract, incomplete or function types. | -- |
- | ::boost::is_convertible<T,U>::value |
- Evaluates to true if an imaginary
- lvalue of type T is convertible to type U. Type T must not be an incomplete - type. -Type U must not be an incomplete, abstract or function type. -No types are considered to be convertible to an array type. - |
- 4 -8.5 - |
- Note that this template is - currently broken with Borland C++ Builder 5 (and earlier), for - constructor-based conversions, and for the Metrowerks 7 (and earlier) compiler - in all cases. | -- |
- | ::boost::is_base_of<T,U>::value |
- Evaluates to true if type T is a base class to type U. Will - detect non-public base classes, and ambiguous base classes. -Note that a class is not considered to be it's own base class, likewise, if - either T or U are non-class types, then the result will always be false. -Types T and U must not be incomplete types. - |
- 10 | -If the compiler does not support - partial-specialization of class templates, then this template can not be used - with function types. - |
- - |
Note that both is_convertible
, and is_base_of
can
- produce compiler errors if the convertion is ambiguous:
struct A {}; -struct B : A {}; -struct C : A {}; -struct D : B, C {}; -bool const x = boost::is_base_of<A,D>::value; // error -bool const y = boost::is_convertible<D*,A*>::value; // error --
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:
-- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- | ::boost::remove_const<T>::type |
- Creates a type the same as T but - with any top level const qualifier removed. For example "const int" would - become "int", but "const int*" would remain unchanged. | -3.9.3 | -If the compiler does not support - partial-specialization of class templates, then this template will compile, but - will have no effect, except where noted below. - |
- - |
- | ::boost::remove_volatile<T>::type |
- Creates a type the same as T but - with any top level volatile qualifier removed. For example "volatile int" would - become "int". | -3.9.3 - |
- If the compiler does not support - partial-specialization of class templates, then this template will compile, but - will have no effect, except where noted below. - |
- - |
- | ::boost::remove_cv<T>::type |
- Creates a type the same as T but with any top level - cv-qualifiers removed. For example "const volatile int" would become "int". | -3.9.3 | -If the compiler does not support - partial-specialization of class templates, then this template will compile, but - will have no effect, except where noted below. - |
- - |
- | ::boost::remove_reference<T>::type |
- If T is a reference type then - removes the reference, otherwise leaves T unchanged. For example "int&" - becomes "int" but "int*" remains unchanged. | -8.3.2 | -If the compiler does not support - partial-specialization of class templates, then this template will compile, but - will have no effect, except where noted below. - |
- - |
- | ::boost::remove_extent<T>::type |
- If T is an array type then removes - the top level array qualifier from T, otherwise leaves T unchanged. For example - "int[2][3]" becomes "int[3]". | -8.3.4 | -If the compiler does not support - partial-specialization of class templates, then this template will compile, but - will have no effect. - |
- - |
- | ::boost::remove_all_extents<T>::type |
- If T is an array type then removes - the all the array qualifiers from T, otherwise leaves T unchanged. For example - "int[2][3]" becomes "int". | -8.3.4 | -
- If the compiler does not support partial-specialization of class - templates, then this template will compile, but will have no effect. - |
- - |
- | ::boost::remove_pointer<T>::type |
- If T is a pointer type, then - removes the top-level indirection from T, otherwise leaves T unchanged. For - example "int*" becomes "int", but "int&" remains unchanged. | -8.3.1 | -If the compiler does not support - partial-specialization of class templates, then this template will compile, but - will have no effect, except where noted below. - |
- - |
- | ::boost::add_reference<T>::type |
- If T is a reference type then - leaves T unchanged, otherwise converts T to a reference type. For example - "int&" remains unchanged, but "double" becomes "double&". | -8.3.2 | -- | - |
- | ::boost::add_pointer<T>::type |
- A type that is the same as
-
-
- remove_reference <T>::type* .
- For example "int" and "int&" both become "int*". |
- 8.3.1 | -If the compiler does not support - partial-specialization of class templates, then this template will not compile - with reference types. - |
- - |
- | ::boost::add_const<T>::type |
- The same as "T const" for all T. | -3.9.3 | -- | - |
- | ::boost::add_volatile<T>::type |
- The same as "T volatile" for all T. | -3.9.3 | -- | - |
- | ::boost::add_cv<T>::type |
- The same as "T const volatile" for all T. | -3.9.3 | -- | - |
As the table above indicates, support for partial specialization of class - templates is required to correctly implement the type transformation templates. - 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
-The first part guarantees the successful compilation of something like this:
-BOOST_STATIC_ASSERT((is_same<char, remove_reference<char&>::type>::value));-
BOOST_STATIC_ASSERT((is_same<char const, remove_reference<char const&>::type>::value));-
BOOST_STATIC_ASSERT((is_same<char volatile, remove_reference<char volatile&>::type>::value));-
BOOST_STATIC_ASSERT((is_same<char const volatile, remove_reference<char const volatile&>::type>::value));-
BOOST_STATIC_ASSERT((is_same<char*, remove_reference<char*&>::type>::value));-
BOOST_STATIC_ASSERT((is_same<char const*, remove_reference<char const*&>::type>::value));-
...-
BOOST_STATIC_ASSERT((is_same<char const volatile* const volatile* const volatile, remove_reference<char const volatile* const volatile* const volatile&>::type>::value));-
and the second part provides library's users with a mechanism to make the above - code work not only for 'char', 'int' or other built-in type, but for they own - types too:
-struct my {};-
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(my)-
BOOST_STATIC_ASSERT((is_same<my, remove_reference<my&>::type>::value));-
BOOST_STATIC_ASSERT((is_same<my, remove_const<my const>::type>::value));-
// etc.-
Note that the macro BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION evaluates - to nothing on those compilers that do support partial specialization.
-The following template synthesizes a type with the desired properties. -
-- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- | ::boost::type_with_alignment<Align>::type |
- Attempts to find a built-in or POD - type with an alignment that is a multiple of Align. - | -- | - | - |
- | ::boost::aligned_storage<Size,Align>::type |
- Attempts to find a POD type of size - Size, and alignment Align. | -- | - | - |
The ::boost::function_traits
class template extracts information
- from function types.
-
- | Expression - |
- Description - |
- Reference - |
- Compiler - requirements - |
- - |
- | ::boost::function_traits<F>::arity |
- Determine the arity of the function
- type F .
- |
- - | Without partial specialisation support, this - template does not compile for reference types. | -- |
- | ::boost::function_traits<F>::result_type |
- The type returned by function type
- F .
- |
- - | Does not compile without support for partial - specialization of class templates. | -- |
- | ::boost::function_traits<F>::arg N _type |
- The N th
- argument type of function type F , where 1<= N <= arity
- of F . |
- - | Does not compile without support for partial - specialization of class templates. | -- |
The type traits library is normally included with:
-#include <boost/type_traits.hpp>-
However the library is actually split up into a number of smaller headers, - sometimes it can be convenient to include one of these directly in order to get - just those type traits classes you actually need. The split headers - always have the same name as the template you require, and are located in - boost/type_traits/. So if for example some code requires - is_class<>, then just include:
-<boost/type_traits/is_class.hpp>-
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::mpl::true_ or boost::mpl::false_ as appropriate:
-# include <boost/type_traits/is_pod.hpp> -# include <boost/type_traits/is_class.hpp> -# include <boost/type_traits/is_union.hpp> - -struct my_pod{}; -struct my_union -{ - char c; - int i; -}; - -namespace boost -{ -template<> -struct is_pod<my_pod> - : public mpl::true_{}; -template<> -struct is_pod<my_union> - : public mpl::true_{}; -template<> -struct is_union<my_union> - : public mpl::true_{}; -template<> -struct is_class<my_union> - : public mpl::false_{}; -} - --
Type-traits comes with four example programs that illustrate some of the ways - in which the type traits templates may be used:
-Demonstrates a version of std::copy that uses memcpy where appropriate to - optimise the copy operation;
-// -// opt::copy -// same semantics as std::copy -// calls memcpy where appropiate. -// - -namespace detail{ - -template<typename I1, typename I2> -I2 copy_imp(I1 first, I1 last, I2 out) -{ - while(first != last) - { - *out = *first; - ++out; - ++first; - } - return out; -} - -template <bool b> -struct copier -{ - template<typename I1, typename I2> - static I2 do_copy(I1 first, I1 last, I2 out) - { return copy_imp(first, last, 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::type_traits::ice_and< - ::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 - >::value>::do_copy(first, last, out); -}-
Demonstrates a version of std::fill that uses memset where appropriate to - optimise fill operations. Also uses call_traits to optimise parameter passing, - to avoid aliasing issues:
-namespace opt{ -// -// fill -// same as std::fill, uses memset where appropriate, along with call_traits -// to "optimise" parameter passing. -// -namespace detail{ - -template <typename I, typename T> -void do_fill_(I first, I last, typename boost::call_traits<T>::param_type val) -{ - while(first != last) - { - *first = val; - ++first; - } -} - -template <bool opt> -struct filler -{ - template <typename I, typename T> - struct rebind - { - static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val) - { do_fill_<I,T>(first, last, val); } - }; -}; - -template <> -struct filler<true> -{ - template <typename I, typename T> - struct rebind - { - static void do_fill(I first, I last, T val) - { - std::memset(first, val, last-first); - } - }; -}; - -} - -template <class I, class T> -inline void fill(I first, I last, const T& val) -{ - typedef detail::filler< - ::boost::type_traits::ice_and< - ::boost::is_pointer<I>::value, - ::boost::is_arithmetic<T>::value, - (sizeof(T) == 1) - >::value> filler_t; - typedef typename filler_t:: template rebind<I,T> binder; - binder::do_fill(first, last, val); -} - -}; // namespace opt-
Demonstrates a version of std::iter_swap that works with proxying iterators, as - well as regular ones; calls std::swap for regular iterators, otherwise does a - "slow but safe" swap:
-namespace opt{ -// -// iter_swap: -// tests whether iterator is a proxying iterator or not, and -// uses optimal form accordingly: -// -namespace detail{ - -template <bool b> -struct swapper -{ - template <typename I> - static void do_swap(I one, I two) - { - typedef typename std::iterator_traits<I>::value_type v_t; - v_t v = *one; - *one = *two; - *two = v; - } -}; - -template <> -struct swapper<true> -{ - template <typename I> - static void do_swap(I one, I two) - { - using std::swap; - swap(*one, *two); - } -}; - -} - -template <typename I1, typename I2> -inline void iter_swap(I1 one, I2 two) -{ - typedef typename std::iterator_traits<I1>::reference r1_t; - typedef typename std::iterator_traits<I2>::reference r2_t; - detail::swapper< - ::boost::type_traits::ice_and< - ::boost::is_reference<r1_t>::value, - ::boost::is_reference<r2_t>::value, - ::boost::is_same<r1_t, r2_t>::value - >::value>::do_swap(one, two); -} - -}; // namespace opt-
This algorithm is the reverse of std::unitialized_copy; it takes a block of - initialized memory and calls destructors on all objects therein. This would - typically be used inside container classes that manage their own memory:
-namespace opt{ -// -// 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 <bool> -struct array_destroyer -{ - template <class T> - static void destroy_array(T* i, T* j){ do_destroy_array(i, j); } -}; - -template <> -struct array_destroyer<true> -{ - template <class T> - static void destroy_array(T*, T*){} -}; - -template <class T> -void do_destroy_array(T* first, T* last) -{ - while(first != last) - { - first->~T(); - ++first; - } -} - -}; // namespace detail - -template <class T> -inline void destroy_array(T* p1, T* p2) -{ - detail::array_destroyer<boost::has_trivial_destructor<T>::value>::destroy_array(p1, p2); -} -} // namespace opt-
Revised 22 April 2001
-Documentation © Copyright John Maddock 2001. Permission to copy, use, modify, - sell and distribute this document is granted provided this copyright notice - appears in all copies. This document is provided "as is" without express or - implied warranty, and with no claim as to its suitability for any purpose.
-The type traits library is based on contributions by Steve Cleary, Beman Dawes, - Aleksey Gurtovoy, Howard Hinnant, Jesse Jones, Mat Marcus, John Maddock and - Jeremy Siek.
-Mat Marcus and Jesse Jones have worked on, and published a - paper describing the partial specialisation workarounds used in this - library.
-The is_convertible template is based on code originally devised by Andrei - Alexandrescu, see "Generic<Programming>: - Mappings between Types and Values".
-Maintained by John Maddock, the - latest version of this file can be found at www.boost.org, - and the boost discussion list at boost@lists.boost.org - (see http://www.boost.org/more/mailing_lists.htm#main).
- + + + + + Automatic redirection failed, please go to + ../../doc/html/boost_typetraits.html + or view the online version at + http://www.boost.org/regression-logs/cs-win32_metacomm/doc/html/boost_typetraits.html + + + +