⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 type_traits.qbk

📁 C++的一个好库。。。现在很流行
💻 QBK
📖 第 1 页 / 共 5 页
字号:
[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
        <ulink url="http://www.boost.org/LICENSE_1_0.txt">
            http://www.boost.org/LICENSE_1_0.txt
        </ulink>)
    ]
    [authors [authors, various]]
    [category template]
    [category generic]
    [last-revision $Date: 2005/08/24 16:49:32 $]
]

[def __boost_root ../../../../]
[def __tof '''<replaceable><link linkend="boost_typetraits.integral_constant">true_type</link>-or-<link linkend="boost_typetraits.integral_constant">false_type</link></replaceable>''']
[def __below '''<replaceable>see-below</replaceable>''']
[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]

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<T>` inherits from `__true_type` only if `T` is `void`.

   template <typename T> 
   struct __is_void : public __false_type{};

   template <> 
   struct __is_void<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<T>`: 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 <typename T> 
   struct __is_pointer : public __false_type{};

   template <typename T> 
   struct __is_pointer<T*> : 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 <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 specialization consider the class 
`remove_extent<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_extent
   { typedef T type; };

   template <typename T, std::size_t N> 
   struct __remove_extent<T[N]>
   { 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<int[4][5]>::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<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:

* 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<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 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<value_type>()` 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<const T*, T*>` (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 <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) { }
   };

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -