background.qbk

来自「Boost provides free peer-reviewed portab」· QBK 代码 · 共 323 行 · 第 1/2 页

QBK
323
字号
[/   Copyright 2007 John Maddock.  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).][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` 

⌨️ 快捷键说明

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