diff --git a/Assignable.html b/Assignable.html deleted file mode 100644 index c3109df..0000000 --- a/Assignable.html +++ /dev/null @@ -1,116 +0,0 @@ - - -
--T - | --is type that is a model of Assignable - | -
-t - | --is an object of type T - | -
-u - | --is an object of type T or possibly const T - | -
-Name - | --Expression - | --Return type - | --Semantics - | -
---|---|---|---|
-Assignment - | --t = u - | --T& - | --t is equivalent to u - | -
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
-T - | --is type that is a model of CopyConstructible - | -
-t - | --is an object of type T - | -
-u - | --is an object of type const T - | -
-Name - | --Expression - | --Return type - | --Semantics - | -
---|---|---|---|
-Copy constructor - | --T(t) - | --T - | --t is equivalent to T(t) - | -
-Copy constructor - | -
--T(u) -- |
--T - | --u is equivalent to T(u) - | -
-Destructor - | -
--t.~T() -- |
--T - | -- - | -
-Address Operator - | -
--&t -- |
--T* - | --denotes the address of t - | -
-Address Operator - | -
--&u -- |
--T* - | --denotes the address of u - | -
- template <class T> - struct CopyConstructibleConcept - { - void constraints() { - T a(b); // require copy constructor - T* ptr = &a; // require address of operator - const_constraints(a); - ignore_unused_variable_warning(ptr); - } - void const_constraints(const T& a) { - T c(a); // require const copy constructor - const T* ptr = &a; // require const address of operator - ignore_unused_variable_warning(c); - ignore_unused_variable_warning(ptr); - } - T b; - }; -- -
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
-X - | --A type that is a model of LessThanComparable - | -
-x, y, z - | --Object of type X - | -
-If operator< is a strict weak ordering, and if each equivalence class -has only a single element, then operator< is a total ordering. -
-Name - | --Expression - | --Type requirements - | --Return type - | -
---|---|---|---|
-Less - | --x < y - | -- - | --Convertible to bool - | -
-Name - | --Expression - | --Precondition - | --Semantics - | --Postcondition - | -
---|---|---|---|---|
-Less - | --x < y - | --x and y are in the domain of < - | -- - | -
-Irreflexivity - | --x < x must be false. - | -
-Antisymmetry - | --x < y implies !(y < x) [2] - | -
-Transitivity - | --x < y and y < z implies x < z [3] - | -
[1] -Only operator< is fundamental; the other inequality operators -are essentially syntactic sugar. -
[2] -Antisymmetry is a theorem, not an axiom: it follows from -irreflexivity and transitivity. -
[3] -Because of irreflexivity and transitivity, operator< always -satisfies the definition of a partial ordering. The definition of -a strict weak ordering is stricter, and the definition of a -total ordering is stricter still. -
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
I think that introducing MultiPassInputIterator isn't the right -solution. Do you also want to define MultiPassBidirectionnalIterator -and MultiPassRandomAccessIterator ? I don't, definitly. It only -confuses the issue. The problem lies into the existing hierarchy of -iterators, which mixes movabillity, modifiabillity and lvalue-ness, -and these are clearly independant. - -
The terms Forward, Bidirectionnal and RandomAccess are about -movabillity and shouldn't be used to mean anything else. In a -completly orthogonal way, iterators can be immutable, mutable, or -neither. Lvalueness of iterators is also orthogonal with -immutabillity. With these clean concepts, your MultiPassInputIterator -is just called a ForwardIterator. - -
-Other translations are:
-std::ForwardIterator -> ForwardIterator & LvalueIterator
-std::BidirectionnalIterator -> BidirectionnalIterator & LvalueIterator
-std::RandomAccessIterator -> RandomAccessIterator & LvalueIterator
-
-
-Note that in practice the only operation not allowed on my -ForwardIterator which is allowed on std::ForwardIterator is -&*it. I think that &* is rarely needed in generic code. - -
-reply by Jeremy Siek: - -
-The above analysis by Valentin is right on. Of course, there is
-the problem with backward compatibility. The current STL implementations
-are based on the old definition of ForwardIterator. The right course
-of action is to get ForwardIterator, etc. changed in the C++ standard.
-Once that is done we can drop MultiPassInputIterator.
-
-
-
-
Copyright © 2000 | -Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) - |
by John Maddock and Steve Cleary
-This is a draft of an article that will appear in a future -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
- - - - diff --git a/call_traits.htm b/call_traits.htm deleted file mode 100644 index 78cb60f..0000000 --- a/call_traits.htm +++ /dev/null @@ -1,754 +0,0 @@ - - - - - - -All of the contents of <boost/call_traits.hpp> are -defined inside namespace boost.
- -The template class call_traits<T> encapsulates the -"best" method to pass a parameter of some type T to or -from a function, and consists of a collection of typedefs defined -as in the table below. The purpose of call_traits is to ensure -that problems like "references to references" -never occur, and that parameters are passed in the most efficient -manner possible (see examples). In each -case if your existing practice is to use the type defined on the -left, then replace it with the call_traits defined type on the -right.
- -Note that for compilers that do not support either partial -specialization or member templates, no benefit will occur from -using call_traits: the call_traits defined types will always be -the same as the existing practice in this case. In addition if -only member templates and not partial template specialisation is -support by the compiler (for example Visual C++ 6) then call_traits -can not be used with array types (although it can be used to -solve the reference to reference problem).
- -Existing practice - |
- call_traits equivalent - |
- Description - |
- Notes - |
-
T |
-
|
- Defines a type that - represents the "value" of type T. Use this for - functions that return by value, or possibly for stored - values of type T. | -2 - |
-
T& |
-
|
- Defines a type that - represents a reference to type T. Use for functions that - would normally return a T&. | -1 - |
-
const T& |
-
|
- Defines a type that - represents a constant reference to type T. Use for - functions that would normally return a const T&. | -1 - |
-
const T& |
-
|
- Defines a type that - represents the "best" way to pass a parameter - of type T to a function. | -1,3 - |
-
Notes:
- -value_type
- as a "constant pointer to type" rather than an
- "array of type" (requires partial
- specialization). Note that if you are using value_type as
- a stored value then this will result in storing a "constant
- pointer to an array" rather than the array itself.
- This may or may not be a good thing depending upon what
- you actually need (in other words take care!).param_type
- is defined as T const
, instead of T
- const&
. This can improve the ability of the
- compiler to optimize loops in the body of the function if
- they depend upon the passed parameter, the semantics of
- the passed parameter is otherwise unchanged (requires
- partial specialization).- -
The following table defines which call_traits types can always -be copy-constructed from which other types, those entries marked -with a '?' are true only if and only if T is copy constructible:
- -- | To: - |
- ||||
From: | -T - |
- value_type - |
- reference - |
- const_reference - |
- param_type - |
-
T | -? - |
- ? - |
- Y - |
- Y - |
- Y - |
-
value_type | -? - |
- ? - |
- N - |
- N - |
- Y - |
-
reference | -? - |
- ? - |
- Y - |
- Y - |
- Y - |
-
const_reference | -? - |
- N - |
- N - |
- Y - |
- Y - |
-
param_type | -? - |
- ? - |
- N - |
- N - |
- Y - |
-
- -
If T is an assignable type the following assignments are -possible:
- -- | To: - |
- ||||
From: | -T - |
- value_type - |
- reference - |
- const_reference - |
- param_type - |
-
T | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
value_type | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
reference | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
const_reference | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
param_type | -Y - |
- Y - |
- - - |
- - - |
- - - |
-
- -
The following table shows the effect that call_traits has on -various types, the table assumes that the compiler supports -partial specialization: if it doesn't then all types behave in -the same way as the entry for "myclass", and call_traits -can not be used with reference or array types.
- -- | Call_traits type: - |
- ||||
Original type T - |
- value_type - |
- reference - |
- const_reference - |
- param_type - |
- Applies to: - |
-
myclass - |
- myclass - |
- myclass& - |
- const - myclass& - |
- myclass - const& - |
- All user - defined types. - |
-
int - |
- int - |
- int& - |
- const int& - |
- int const - |
- All small - built-in types. - |
-
int* - |
- int* - |
- int*& - |
- int*const& - |
- int* const - |
- All - pointer types. - |
-
int& - |
- int& - |
- int& - |
- const int& - |
- int& - |
- All - reference types. - |
-
const int& - |
- const int& - |
- const int& - |
- const int& - |
- const int& - |
- All - constant-references. - |
-
int[3] - |
- const int* - |
- int(&)[3] - |
- const int(&)[3] - |
- const int* - const - |
- All array - types. - |
-
const int[3] - |
- const int* - |
- const int(&)[3] - |
- const int(&)[3] - |
- const int* - const - |
- All - constant-array types. - |
-
- -
The following class is a trivial class that stores some type T -by value (see the call_traits_test.cpp -file), the aim is to illustrate how each of the available call_traits -typedefs may be used:
- -template <class T> -struct contained -{ - // define our typedefs first, arrays are stored by value - // so value_type is not the same as result_type: - typedef typename boost::call_traits<T>::param_type param_type; - typedef typename boost::call_traits<T>::reference reference; - typedef typename boost::call_traits<T>::const_reference const_reference; - typedef T value_type; - typedef typename boost::call_traits<T>::value_type result_type; - - // stored value: - value_type v_; - - // constructors: - contained() {} - contained(param_type p) : v_(p){} - // return byval: - result_type value() { return v_; } - // return by_ref: - reference get() { return v_; } - const_reference const_get()const { return v_; } - // pass value: - void call(param_type p){} - -};- -
Consider the definition of std::binder1st:
- -template <class Operation> -class binder1st : - public unary_function<Operation::second_argument_type, Operation::result_type> -{ -protected: - Operation op; - Operation::first_argument_type value; -public: - binder1st(const Operation& x, const Operation::first_argument_type& y); - Operation::result_type operator()(const Operation::second_argument_type& x) const; -};- -
Now consider what happens in the relatively common case that
-the functor takes its second argument as a reference, that
-implies that Operation::second_argument_type
is a
-reference type, operator()
will now end up taking a
-reference to a reference as an argument, and that is not
-currently legal. The solution here is to modify operator()
-to use call_traits:
Operation::result_type operator()(call_traits<Operation::second_argument_type>::param_type x) const;- -
Now in the case that Operation::second_argument_type
-is a reference type, the argument is passed as a reference, and
-the no "reference to reference" occurs.
If we pass the name of an array as one (or both) arguments to std::make_pair
,
-then template argument deduction deduces the passed parameter as
-"const reference to array of T", this also applies to
-string literals (which are really array literals). Consequently
-instead of returning a pair of pointers, it tries to return a
-pair of arrays, and since an array type is not copy-constructible
-the code fails to compile. One solution is to explicitly cast the
-arguments to make_pair to pointers, but call_traits provides a
-better (i.e. automatic) solution (and one that works safely even
-in generic code where the cast might do the wrong thing):
template <class T1, class T2> -std::pair< - typename boost::call_traits<T1>::value_type, - typename boost::call_traits<T2>::value_type> - make_pair(const T1& t1, const T2& t2) -{ - return std::pair< - typename boost::call_traits<T1>::value_type, - typename boost::call_traits<T2>::value_type>(t1, t2); -}- -
Here, the deduced argument types will be automatically -degraded to pointers if the deduced types are arrays, similar -situations occur in the standard binders and adapters: in -principle in any function that "wraps" a temporary -whose type is deduced. Note that the function arguments to make_pair -are not expressed in terms of call_traits: doing so would prevent -template argument deduction from functioning.
- -The call_traits template will "optimize" the passing -of a small built-in type as a function parameter, this mainly has -an effect when the parameter is used within a loop body. In the -following example (see algo_opt_examples.cpp), -a version of std::fill is optimized in two ways: if the type -passed is a single byte built-in type then std::memset is used to -effect the fill, otherwise a conventional C++ implemention is -used, but with the passed parameter "optimized" using -call_traits:
- -namespace detail{ - -template <bool opt> -struct filler -{ - template <typename I, typename T> - static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val); - { - while(first != last) - { - *first = val; - ++first; - } - } -}; - -template <> -struct filler<true> -{ - template <typename I, typename T> - static void do_fill(I first, I last, T val) - { - memset(first, val, last-first); - } -}; - -} - -template <class I, class T> -inline void fill(I first, I last, const T& val) -{ - enum{ can_opt = boost::is_pointer<I>::value - && boost::is_arithmetic<T>::value - && (sizeof(T) == 1) }; - typedef detail::filler<can_opt> filler_t; - filler_t::template do_fill<I,T>(first, last, val); -}- -
Footnote: the reason that this is "optimal" for -small built-in types is that with the value passed as "T -const" instead of "const T&" the compiler is -able to tell both that the value is constant and that it is free -of aliases. With this information the compiler is able to cache -the passed value in a register, unroll the loop, or use -explicitly parallel instructions: if any of these are supported. -Exactly how much mileage you will get from this depends upon your -compiler - we could really use some accurate benchmarking -software as part of boost for cases like this.
- -Note that the function arguments to fill are not expressed in -terms of call_traits: doing so would prevent template argument -deduction from functioning. Instead fill acts as a "thin -wrapper" that is there to perform template argument -deduction, the compiler will optimise away the call to fill all -together, replacing it with the call to filler<>::do_fill, -which does use call_traits.
- -The following notes are intended to briefly describe the -rational behind choices made in call_traits.
- -All user-defined types follow "existing practice" -and need no comment.
- -Small built-in types (what the standard calls fundamental -types [3.9.1]) differ from existing practice only in the param_type -typedef. In this case passing "T const" is compatible -with existing practice, but may improve performance in some cases -(see Example 4), in any case this should never -be any worse than existing practice.
- -Pointers follow the same rational as small built-in types.
- -For reference types the rational follows Example -2 - references to references are not allowed, so the call_traits -members must be defined such that these problems do not occur. -There is a proposal to modify the language such that "a -reference to a reference is a reference" (issue #106, -submitted by Bjarne Stroustrup), call_traits<T>::value_type -and call_traits<T>::param_type both provide the same effect -as that proposal, without the need for a language change (in -other words it's a workaround).
- -For array types, a function that takes an array as an argument -will degrade the array type to a pointer type: this means that -the type of the actual parameter is different from its declared -type, something that can cause endless problems in template code -that relies on the declared type of a parameter. For example:
- -template <class T> -struct A -{ - void foo(T t); -};- -
In this case if we instantiate A<int[2]> -then the declared type of the parameter passed to member function -foo is int[2], but it's actual type is const int*, if we try to -use the type T within the function body, then there is a strong -likelyhood that our code will not compile:
- -template <class T> -void A<T>::foo(T t) -{ - T dup(t); // doesn't compile for case that T is an array. -}- -
By using call_traits the degradation from array to pointer is -explicit, and the type of the parameter is the same as it's -declared type:
- -template <class T> -struct A -{ - void foo(call_traits<T>::value_type t); -}; - -template <class T> -void A<T>::foo(call_traits<T>::value_type t) -{ - call_traits<T>::value_type dup(t); // OK even if T is an array type. -}- -
For value_type (return by value), again only a pointer may be -returned, not a copy of the whole array, and again call_traits -makes the degradation explicit. The value_type member is useful -whenever an array must be explicitly degraded to a pointer - Example 3 provides the test case (Footnote: the -array specialisation for call_traits is the least well understood -of all the call_traits specialisations, if the given semantics -cause specific problems for you, or don't solve a particular -array-related problem, then I would be interested to hear about -it. Most people though will probably never need to use this -specialisation).
- -Revised 01 September 2000
- -© Copyright boost.org 2000. 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.
- -Based on contributions by Steve Cleary, Beman Dawes, Howard -Hinnant and John Maddock.
- -Maintained by John -Maddock, the latest version of this file can be found at www.boost.org, and the boost -discussion list at www.egroups.com/list/boost.
- -.
- -- -
- - diff --git a/call_traits_test.cpp b/call_traits_test.cpp deleted file mode 100644 index 0c7155e..0000000 --- a/call_traits_test.cpp +++ /dev/null @@ -1,366 +0,0 @@ - // boost::compressed_pair test program - - // (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and - // distribute this software is granted provided this copyright notice appears - // in all copies. This software is provided "as is" without express or implied - // warranty, and with no claim as to its suitability for any purpose. - -// standalone test program for
All of the contents of <boost/compressed_pair.hpp> are -defined inside namespace boost.
- -The class compressed pair is very similar to std::pair, but if -either of the template arguments are empty classes, then the -"empty member optimisation" is applied to compress the -size of the pair.
- -template <class T1, class T2> -class compressed_pair -{ -public: - typedef T1 first_type; - typedef T2 second_type; - typedef typename call_traits<first_type>::param_type first_param_type; - typedef typename call_traits<second_type>::param_type second_param_type; - typedef typename call_traits<first_type>::reference first_reference; - typedef typename call_traits<second_type>::reference second_reference; - typedef typename call_traits<first_type>::const_reference first_const_reference; - typedef typename call_traits<second_type>::const_reference second_const_reference; - - compressed_pair() : base() {} - compressed_pair(first_param_type x, second_param_type y); - explicit compressed_pair(first_param_type x); - explicit compressed_pair(second_param_type y); - - first_reference first(); - first_const_reference first() const; - - second_reference second(); - second_const_reference second() const; - - void swap(compressed_pair& y); -};- -
The two members of the pair can be accessed using the member -functions first() and second(). Note that not all member -functions can be instantiated for all template parameter types. -In particular compressed_pair can be instantiated for reference -and array types, however in these cases the range of constructors -that can be used are limited. If types T1 and T2 are the same -type, then there is only one version of the single-argument -constructor, and this constructor initialises both values in the -pair to the passed value.
- -Note that compressed_pair can not be instantiated if either of -the template arguments is an enumerator type, unless there is -compiler support for boost::is_enum, or if boost::is_enum is -specialised for the enumerator type.
- -Finally, compressed_pair requires compiler support for partial -specialisation of class templates - without that support -compressed_pair behaves just like std::pair.
- -Revised 08 March 2000
- -© Copyright boost.org 2000. 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.
- -Based on contributions by Steve Cleary, Beman Dawes, Howard -Hinnant and John Maddock.
- -Maintained by John -Maddock, the latest version of this file can be found at www.boost.org, and the boost -discussion list at www.egroups.com/list/boost.
- -- - diff --git a/compressed_pair_test.cpp b/compressed_pair_test.cpp deleted file mode 100644 index 751ab9e..0000000 --- a/compressed_pair_test.cpp +++ /dev/null @@ -1,159 +0,0 @@ - // boost::compressed_pair test program - - // (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and - // distribute this software is granted provided this copyright notice appears - // in all copies. This software is provided "as is" without express or implied - // warranty, and with no claim as to its suitability for any purpose. - -// standalone test program for