diff --git a/algo_opt_examples.cpp b/algo_opt_examples.cpp deleted file mode 100644 index c30587c..0000000 --- a/algo_opt_examples.cpp +++ /dev/null @@ -1,424 +0,0 @@ - -/* - * - * Copyright (c) 1999 - * Dr John Maddock - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Dr John Maddock makes no representations - * about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. - * - * This file provides some example of type_traits usage - - * by "optimising" various algorithms: - * - * opt::copy - optimised for trivial copy (cf std::copy) - * opt::fill - optimised for trivial copy/small types (cf std::fill) - * opt::destroy_array - an example of optimisation based upon omitted destructor calls - * opt::iter_swap - uses type_traits to determine whether the iterator is a proxy - * in which case it uses a "safe" approach, otherwise calls swap - * on the assumption that swap may be specialised for the pointed-to type. - * - */ - -/* Release notes: - 23rd July 2000: - Added explicit failure for broken compilers that don't support these examples. - Fixed broken gcc support (broken using directive). - Reordered tests slightly. -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using std::cout; -using std::endl; -using std::cin; - -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -#error "Sorry, without template partial specialisation support there isn't anything to test here..." -#endif - -namespace opt{ - -// -// algorithm destroy_array: -// The reverse of std::unitialized_copy, takes a block of -// unitialized memory and calls destructors on all objects therein. -// - -namespace detail{ - -template -struct array_destroyer -{ - template - static void destroy_array(T* i, T* j){ do_destroy_array(i, j); } -}; - -template <> -struct array_destroyer -{ - template - static void destroy_array(T*, T*){} -}; - -template -void do_destroy_array(T* first, T* last) -{ - while(first != last) - { - first->~T(); - ++first; - } -} - -}; // namespace detail - -template -inline void destroy_array(T* p1, T* p2) -{ - detail::array_destroyer::value>::destroy_array(p1, p2); -} - -// -// unoptimised versions of destroy_array: -// -template -void destroy_array1(T* first, T* last) -{ - while(first != last) - { - first->~T(); - ++first; - } -} -template -void destroy_array2(T* first, T* last) -{ - for(; first != last; ++first) first->~T(); -} - - -// -// opt::copy -// same semantics as std::copy -// calls memcpy where appropiate. -// - -namespace detail{ - -template -struct copier -{ - template - static I2 do_copy(I1 first, I1 last, I2 out); -}; - -template -template -I2 copier::do_copy(I1 first, I1 last, I2 out) -{ - while(first != last) - { - *out = *first; - ++out; - ++first; - } - return out; -} - -template <> -struct copier -{ - template - static I2* do_copy(I1* first, I1* last, I2* out) - { - memcpy(out, first, (last-first)*sizeof(I2)); - return out+(last-first); - } -}; - - -} - -template -inline I2 copy(I1 first, I1 last, I2 out) -{ - typedef typename boost::remove_cv::value_type>::type v1_t; - typedef typename boost::remove_cv::value_type>::type v2_t; - enum{ can_opt = boost::is_same::value - && boost::is_pointer::value - && boost::is_pointer::value - && boost::has_trivial_assign::value }; - return detail::copier::do_copy(first, last, out); -} - -// -// fill -// same as std::fill, uses memset where appropriate, along with call_traits -// to "optimise" parameter passing. -// -namespace detail{ - -template -struct filler -{ - template - static void do_fill(I first, I last, typename boost::call_traits::param_type val); - }; - -template -template -void filler::do_fill(I first, I last, typename boost::call_traits::param_type val) -{ - while(first != last) - { - *first = val; - ++first; - } -} - -template <> -struct filler -{ - template - static void do_fill(I first, I last, T val) - { - std::memset(first, val, last-first); - } -}; - -} - -template -inline void fill(I first, I last, const T& val) -{ - enum{ can_opt = boost::is_pointer::value - && boost::is_arithmetic::value - && (sizeof(T) == 1) }; - typedef detail::filler filler_t; - filler_t::template do_fill(first, last, val); -} - -// -// iter_swap: -// tests whether iterator is a proxying iterator or not, and -// uses optimal form accordingly: -// -namespace detail{ - -template -struct swapper -{ - template - static void do_swap(I one, I two) - { - typedef typename std::iterator_traits::value_type v_t; - v_t v = *one; - *one = *two; - *two = v; - } -}; - -#ifdef __GNUC__ -using std::swap; -#endif - -template <> -struct swapper -{ - template - static void do_swap(I one, I two) - { - using std::swap; - swap(*one, *two); - } -}; - -} - -template -inline void iter_swap(I1 one, I2 two) -{ - typedef typename std::iterator_traits::reference r1_t; - typedef typename std::iterator_traits::reference r2_t; - enum{ can_opt = boost::is_reference::value && boost::is_reference::value && boost::is_same::value }; - detail::swapper::do_swap(one, two); -} - - -}; // namespace opt - -// -// define some global data: -// -const int array_size = 1000; -int i_array[array_size] = {0,}; -const int ci_array[array_size] = {0,}; -char c_array[array_size] = {0,}; -const char cc_array[array_size] = { 0,}; - -const int iter_count = 1000000; - - -int main() -{ - // - // test destroy_array, - // compare destruction time of an array of ints - // with unoptimised form. - // - cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl; - cout << "testing destroy_array...\n" - "[Some compilers may be able to optimise the \"unoptimised\"\n versions as well as type_traits does.]" << endl; - /*cache load*/ opt::destroy_array(i_array, i_array + array_size); - boost::timer t; - double result; - int i; - for(i = 0; i < iter_count; ++i) - { - opt::destroy_array(i_array, i_array + array_size); - } - result = t.elapsed(); - cout << "destroy_array: " << result << endl; - /*cache load*/ opt::destroy_array1(i_array, i_array + array_size); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::destroy_array1(i_array, i_array + array_size); - } - result = t.elapsed(); - cout << "destroy_array(unoptimised#1): " << result << endl; - /*cache load*/ opt::destroy_array2(i_array, i_array + array_size); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::destroy_array2(i_array, i_array + array_size); - } - result = t.elapsed(); - cout << "destroy_array(unoptimised#2): " << result << endl << endl; - - cout << "testing fill(char)...\n" - "[Some standard library versions may already perform this optimisation.]" << endl; - /*cache load*/ opt::fill(c_array, c_array + array_size, (char)3); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::fill(c_array, c_array + array_size, (char)3); - } - result = t.elapsed(); - cout << "opt::fill: " << result << endl; - /*cache load*/ std::fill(c_array, c_array + array_size, (char)3); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - std::fill(c_array, c_array + array_size, (char)3); - } - result = t.elapsed(); - cout << "std::fill: " << result << endl << endl; - - cout << "testing fill(int)...\n" - "[Tests the effect of call_traits pass-by-value optimisation -\nthe value of this optimisation may depend upon hardware characteristics.]" << endl; - /*cache load*/ opt::fill(i_array, i_array + array_size, 3); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::fill(i_array, i_array + array_size, 3); - } - result = t.elapsed(); - cout << "opt::fill: " << result << endl; - /*cache load*/ std::fill(i_array, i_array + array_size, 3); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - std::fill(i_array, i_array + array_size, 3); - } - result = t.elapsed(); - cout << "std::fill: " << result << endl << endl; - - cout << "testing copy...\n" - "[Some standard library versions may already perform this optimisation.]" << endl; - /*cache load*/ opt::copy(ci_array, ci_array + array_size, i_array); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::copy(ci_array, ci_array + array_size, i_array); - } - result = t.elapsed(); - cout << "opt::copy: " << result << endl; - /*cache load*/ std::copy(ci_array, ci_array + array_size, i_array); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - std::copy(ci_array, ci_array + array_size, i_array); - } - result = t.elapsed(); - cout << "std::copy: " << result << endl; - /*cache load*/ opt::detail::copier::template do_copy(ci_array, ci_array + array_size, i_array); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::detail::copier::template do_copy(ci_array, ci_array + array_size, i_array); - } - result = t.elapsed(); - cout << "standard \"unoptimised\" copy: " << result << endl << endl; - - /*cache load*/ opt::copy(cc_array, cc_array + array_size, c_array); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::copy(cc_array, cc_array + array_size, c_array); - } - result = t.elapsed(); - cout << "opt::copy: " << result << endl; - /*cache load*/ std::copy(cc_array, cc_array + array_size, c_array); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - std::copy(cc_array, cc_array + array_size, c_array); - } - result = t.elapsed(); - cout << "std::copy: " << result << endl; - /*cache load*/ opt::detail::copier::template do_copy(cc_array, cc_array + array_size, c_array); - t.restart(); - for(i = 0; i < iter_count; ++i) - { - opt::detail::copier::template do_copy(cc_array, cc_array + array_size, c_array); - } - result = t.elapsed(); - cout << "standard \"unoptimised\" copy: " << result << endl << endl; - - - // - // testing iter_swap - // really just a check that it does in fact compile... - std::vector v1; - v1.push_back(0); - v1.push_back(1); - std::vector v2; - v2.push_back(0); - v2.push_back(1); - opt::iter_swap(v1.begin(), v1.begin()+1); - opt::iter_swap(v2.begin(), v2.begin()+1); - - cout << "Press any key to exit..."; - cin.get(); -} - - - - - - diff --git a/c++_type_traits.htm b/c++_type_traits.htm deleted file mode 100644 index 3cbb786..0000000 --- a/c++_type_traits.htm +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - -C++ Type traits - - - - -

C++ Type traits

-

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.

-

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[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.

-

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 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.

-

Optimised 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[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 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:

-
    -
  • first that the two iterators point to the same type by using a type-traits - class is_same.
  • -
  • Then that both iterators are real pointers - using the class is_pointer - described above.
  • -
  • Finally that the pointed-to types have a trivial assignment operator using - has_trivial_assign.
  • -
-

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.

-

Was it worth it?

-

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:

-
    -
  • If you use the right algorithm for the job in the first place then - optimisation 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 - optimisations may well be worthwhile where they would not be so for a single - case - in other words, the likelihood that the optimisation 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 standardising an algorithm if users reject it on the - grounds that there are better, more heavily optimised versions available.
  • -
-

Table 1: Time taken to copy 1000 elements using copy<const T*, T*> -(times in micro-seconds)

- - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Version

-
-

T

-
-

Time

-
"Optimised" copychar0.99
Conventional copychar8.07
"Optimised" copyint2.52
Conventional copyint8.02
-

 

-

Pair of References

-

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.

-

Conclusion

-

We hope that in this article we have been able to give you some idea of what -type-traits are all about. A more complete listing of the available classes are -in the boost documentation, along with further examples using type traits. -Templates have enabled C++ uses to take the advantage of the code reuse that -generic programming brings; hopefully this article has shown that generic -programming does not have to sink to the lowest common denominator, and that -templates can be optimal as well as generic.

-

Acknowledgements

-

The authors would like to thank Beman Dawes and Howard Hinnant for their -helpful comments when preparing this article.

-

References

-
    -
  1. Nathan C. Myers, C++ Report, June 1995.
  2. -
  3. The type traits library is based upon contributions by Steve Cleary, Beman - Dawes, Howard Hinnant and John Maddock: it can be found at www.boost.org.
  4. -
  5. A scalar type is an arithmetic type (i.e. a built-in integer or floating - point type), an enumeration type, a pointer, a pointer to member, or a - const- or volatile-qualified version of one of these types.
  6. -
  7. This quote is from Donald Knuth, ACM Computing Surveys, December 1974, pg - 268.
  8. -
  9. The test code is available as part of the boost utility library (see - algo_opt_examples.cpp), the code was compiled with gcc 2.95 with all - optimisations turned on, tests were conducted on a 400MHz Pentium II machine - running Microsoft Windows 98.
  10. -
  11. John Maddock and Howard Hinnant have submitted a "compressed_pair" - library to Boost, which uses a technique similar to the one described here - to hold references. Their pair also uses type traits to determine if any of - the types are empty, and will derive instead of contain to conserve space -- - hence the name "compressed".
  12. -
  13. This is actually an issue with the C++ Core Language Working Group (issue - #106), submitted by Bjarne Stroustrup. The tentative resolution is to allow - a "reference to a reference to T" to mean the same thing as a - "reference to T", but only in template instantiation, in a method - similar to multiple cv-qualifiers.
  14. -
  15. For those of you who are wondering why this shouldn't be const-qualified, - remember that references are always implicitly constant (for example, you - can't re-assign a reference). Remember also that "const T &" - is something completely different. For this reason, cv-qualifiers on - template type arguments that are references are ignored.
  16. -
-

Listing 1

-
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/type_traits.htm b/type_traits.htm deleted file mode 100644 index 7564443..0000000 --- a/type_traits.htm +++ /dev/null @@ -1,620 +0,0 @@ - - - - - - -Type Traits - - - - -

Header -<boost/type_traits.hpp>

- -

The contents of <boost/type_traits.hpp> are declared in -namespace boost.

- -

The file <boost/type_traits.hpp> -contains various template classes that describe the fundamental -properties of a type; each class represents a single type -property or a single type transformation. This documentation is -divided up into the following sections:

- -
Fundamental type operations
-Fundamental type properties
-   Miscellaneous
-   cv-Qualifiers
-   Fundamental Types
-   Compound Types
-   Object/Scalar Types
-Compiler Support Information
-Example Code
- -

Fundamental type operations

- -

Usage: "class_name<T>::type" performs -indicated transformation on type T.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Expression.

-

Description.

-

Compiler.

-
remove_volatile<T>::typeCreates a type the same as T - but with any top level volatile qualifier removed. For - example "volatile int" would become "int".

P

-
remove_const<T>::typeCreates a type the same as T - but with any top level const qualifier removed. For - example "const int" would become "int".

P

-
remove_cv<T>::typeCreates a type the same as T - but with any top level cv-qualifiers removed. For example - "const int" would become "int", and - "volatile double" would become "double".

P

-
remove_reference<T>::typeIf T is a reference type - then removes the reference, otherwise leaves T unchanged. - For example "int&" becomes "int" - but "int*" remains unchanged.

P

-
add_reference<T>::typeIf 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&".

P

-
remove_bounds<T>::typeIf 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]".

P

-
- -

 

- -

Fundamental type properties

- -

Usage: "class_name<T>::value" is true if -indicated property is true, false otherwise. (Note that class_name<T>::value -is always defined as a compile time constant).

- -

Miscellaneous

- - - - - - - - - - - - - - - - - - - - - - -

Expression

-

Description

-

Compiler

-
is_same<T,U>::value
-

True if T and U are the - same type.

-
 
is_convertible<T,U>::value
-

True if type T is - convertible to type U.

-
 
alignment_of<T>::value
-

An integral value - representing the minimum alignment requirements of type T - (strictly speaking defines a multiple of the type's - alignment requirement; for all compilers tested so far - however it does return the actual alignment).

-
 
- -

 

- -

cv-Qualifiers

- -

The following classes determine what cv-qualifiers are present -on a type (see 3.93).

- - - - - - - - - - - - - - - - - -

Expression.

-

Description.

-

Compiler.

-
is_const<T>::valueTrue if type T is top-level - const qualified. 
is_volatile<T>::valueTrue if type T is top-level - volatile qualified. 
- -

 

- -

Fundamental Types

- -

The following will only ever be true for cv-unqualified types; -these are closely based on the section 3.9 of the C++ Standard.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Expression.

-

Description.

-

Compiler.

-
is_void<T>::valueTrue only if T is void. 
is_standard_unsigned_integral<T>::valueTrue only if T is one of the - standard unsigned integral types (3.9.1 p3) - unsigned - char, unsigned short, unsigned int, and unsigned long. 
is_standard_signed_integral<T>::valueTrue only if T is one of the - standard signed integral types (3.9.1 p2) - signed char, - short, int, and long. 
is_standard_integral<T>::valueTrue if T is a standard - integral type(3.9.1 p7) - T is either char, wchar_t, bool - or either is_standard_signed_integral<T>::value or - is_standard_integral<T>::value is true. 
is_standard_float<T>::valueTrue if T is one of the - standard floating point types(3.9.1 p8) - float, double - or long double. 
is_standard_arithmetic<T>::valueTrue if T is a standard - arithmetic type(3.9.1 p8) - implies is_standard_integral - or is_standard_float is true. 
is_standard_fundamental<T>::valueTrue if T is a standard - arithmetic type or if T is void. 
is_extension_unsigned_integral<T>::valueTrue for compiler specific - unsigned integral types. 
is_extension_signed_integral<T>>:valueTrue for compiler specific - signed integral types. 
is_extension_integral<T>::valueTrue if either is_extension_unsigned_integral<T>::value - or is_extension_signed_integral<T>::value is true. 
is_extension_float<T>::valueTrue for compiler specific - floating point types. 
is_extension_arithmetic<T>::valueTrue if either is_extension_integral<T>::value - or is_extension_float<T>::value are true. 
 is_extension_fundamental<T>::valueTrue if either is_extension_arithmetic<T>::value - or is_void<T>::value are true. 
 is_unsigned_integral<T>::valueTrue if either is_standard_unsigned_integral<T>::value - or is_extention_unsigned_integral<T>::value are - true. 
is_signed_integral<T>::valueTrue if either is_standard_signed_integral<T>::value - or is_extention_signed_integral<T>>::value are - true. 
is_integral<T>::valueTrue if either is_standard_integral<T>::value - or is_extention_integral<T>::value are true. 
is_float<T>::valueTrue if either is_standard_float<T>::value - or is_extention_float<T>::value are true. 
is_arithmetic<T>::valueTrue if either is_integral<T>::value - or is_float<T>::value are true. 
is_fundamental<T>::valueTrue if either is_arithmetic<T>::value - or is_void<T>::value are true. 
- -

 

- -

Compound Types

- -

The following will only ever be true for cv-unqualified types, -as defined by the Standard. 

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Expression

-

Description

-

Compiler

-
is_array<T>::valueTrue if T is an array type.

P

-
is_pointer<T>::valueTrue if T is a regular - pointer type - including function pointers - but - excluding pointers to member functions (3.9.2 p1 and 8.3.1). 
is_member_pointer<T>::valueTrue if T is a pointer to a - non-static class member (3.9.2 p1 and 8.3.1). 
is_reference<T>::valueTrue if T is a reference - type (3.9.2 p1 and 8.3.2). 
is_class<T>::valueTrue if T is a class or - struct type.

PD

-
is_union<T>::valueTrue if T is a union type.

C

-
is_enum<T>::valueTrue if T is an enumerator - type.

C

-
is_compound<T>::valueTrue if T is any of the - above compound types.

PD

-
- -

 

- -

Object/Scalar Types

- -

The following ignore any top level cv-qualifiers: if class_name<T>::value -is true then class_name<cv-qualified-T>::value -will also be true.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Expression

-

Description

-

Compiler

-
is_object<T>::valueTrue if T is not a reference - type, or a (possibly cv-qualified) void type.

P

-
is_standard_scalar<T>::valueTrue if T is a standard - arithmetic type, an enumerated type, a pointer or a - member pointer.

PD

-
is_extension_scalar<T>::valueTrue if T is an extentions - arithmetic type, an enumerated type, a pointer or a - member pointer.

PD

-
is_scalar<T>::valueTrue if T is an arithmetic - type, an enumerated type, a pointer or a member pointer.

PD

-
is_POD<T>::valueTrue if T is a "Plain - Old Data" type (see 3.9 p2&p3). Note that - although this requires compiler support to be correct in - all cases, if T is a scalar or an array of scalars then - we can correctly define T as a POD.

PC

-
is_empty<T>::valueTrue 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. Screens out enum - types by using is_convertible<T,int>, this means - that empty classes that overload operator int(), will not - be classified as empty.

PCD

-
has_trivial_constructor<T>::valueTrue if T has a trivial - default constructor - that is T() is equivalent to memset.

PC

-
has_trivial_copy<T>::valueTrue if T has a trivial copy - constructor - that is T(const T&) is equivalent to - memcpy.

PC

-
has_trivial_assign<T>::valueTrue if T has a trivial - assignment operator - that is if T::operator=(const T&) - is equivalent to memcpy.

PC

-
has_trivial_destructor<T>::valueTrue if T has a trivial - destructor - that is if T::~T() has no effect.

PC

-
- -

 

- -

Compiler Support Information

- -

The legends used in the tables above have the following -meanings:

- - - - - - - - - - - - - - -

P

-
Denotes that the class - requires support for partial specialisation of class - templates to work correctly.

C

-
Denotes that direct compiler - support for that traits class is required.

D

-
Denotes that the traits - class is dependent upon a class that requires direct - compiler support.
- -

 

- -

For those classes that are marked with a D or C, if compiler -support is not provided, this type trait may return "false" -when the correct value is actually "true". The single -exception to this rule is "is_class", which attempts to -guess whether or not T is really a class, and may return "true" -when the correct value is actually "false". This can -happen if: T is a union, T is an enum, or T is a compiler-supplied -scalar type that is not specialised for in these type traits.

- -

If there is no compiler support, to ensure that these -traits always return the correct values, specialise 'is_enum' -for each user-defined enumeration type, 'is_union' for each user-defined -union type, 'is_empty' for each user-defined empty composite type, -and 'is_POD' for each user-defined POD type. The 'has_*' traits -should also be specialized if the user-defined type has those -traits and is not a POD.

- -

The following rules are automatically enforced:

- -

is_enum implies is_POD

- -

is_POD implies has_*

- -

This means, for example, if you have an empty POD-struct, just -specialize is_empty and is_POD, which will cause all the has_* to -also return true.

- -

Example code

- -

Type-traits comes with two sample programs: type_traits_test.cpp tests the -type traits classes - mostly this is a test of your compiler's -support for the concepts used in the type traits implementation, -while algo_opt_examples.cpp -uses the type traits classes to "optimise" some -familiar standard library algorithms.

- -

There are four algorithm examples in algo_opt_examples.cpp:

- - - - - - - - - - - - - - - - - - -
opt::copy
-
If the copy operation can be - performed using memcpy then does so, otherwise uses a - regular element by element copy (c.f. std::copy).
opt::fill
-
If the fill operation can be - performed by memset, then does so, otherwise uses a - regular element by element assign. Also uses call_traits - to optimise how the parameters can be passed (c.f. - std::fill).
opt::destroy_array
-
If the type in the array has - a trivial destructor then does nothing, otherwise calls - destructors for all elements in the array - this - algorithm is the reverse of std::uninitialized_copy / std::uninitialized_fill.
opt::iter_swap
-
Determines whether the - iterator is a proxy-iterator: if it is then does a "slow - and safe" swap, otherwise calls std::swap on the - assumption that std::swap may be specialised for the - iterated type.
- -

 

- -
- -

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/type_traits_test.cpp b/type_traits_test.cpp deleted file mode 100644 index d44ffeb..0000000 --- a/type_traits_test.cpp +++ /dev/null @@ -1,672 +0,0 @@ -// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & 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 - -/* Release notes: - 31 Jan 2001: - Added a test for is_array using a const array and a test for - is_convertible with a user-defined implicit conversion. Changed - signature of main() so that this program will link under - MSVC. (Jeremy Siek) - 20 Jan 2001: - Suppress an expected warning for MSVC - Added a test to prove that we can use void with is_same<> - Removed "press any key to exit" as it interferes with testing in large - batches. - (David Abahams) - 31st July 2000: - Added extra tests for is_empty, is_convertible, alignment_of. - 23rd July 2000: - Removed all call_traits tests to call_traits_test.cpp - Removed all compressed_pair tests to compressed_pair_tests.cpp - Improved tests macros - Tidied up specialistions of type_types classes for test cases. */ - -#include -#include - -#include -#include -#include "type_traits_test.hpp" - -using namespace boost; - -// Since there is no compiler support, we should specialize: -// is_enum for all enumerations (is_enum implies is_POD) -// is_union for all unions -// is_empty for all empty composites -// is_POD for all PODs (except enums) (is_POD implies has_*) -// has_* for any UDT that has that trait and is not POD - -enum enum_UDT{ one, two, three }; -struct UDT -{ - UDT(); - ~UDT(); - UDT(const UDT&); - UDT& operator=(const UDT&); - int i; - - void f1(); - int f2(); - int f3(int); - int f4(int, float); -}; - -struct POD_UDT { int x; }; -struct empty_UDT{ ~empty_UDT(){}; }; -struct empty_POD_UDT{}; -union union_UDT -{ - int x; - double y; - ~union_UDT(); -}; -union POD_union_UDT -{ - int x; - double y; -}; -union empty_union_UDT -{ - ~empty_union_UDT(); -}; -union empty_POD_union_UDT{}; -#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION -namespace boost { -template <> struct is_enum -{ static const bool value = true; }; -template <> struct is_POD -{ static const bool value = true; }; -// this type is not POD, so we have to specialize the has_* individually -template <> struct has_trivial_constructor -{ static const bool value = true; }; -template <> struct has_trivial_copy -{ static const bool value = true; }; -template <> struct has_trivial_assign -{ static const bool value = true; }; -template <> struct is_POD -{ static const bool value = true; }; -template <> struct is_union -{ static const bool value = true; }; -template <> struct is_union -{ static const bool value = true; }; -template <> struct is_POD -{ static const bool value = true; }; -template <> struct is_union -{ static const bool value = true; }; -// this type is not POD, so we have to specialize the has_* individually -template <> struct has_trivial_constructor -{ static const bool value = true; }; -template <> struct has_trivial_copy -{ static const bool value = true; }; -template <> struct has_trivial_assign -{ static const bool value = true; }; -template <> struct is_union -{ static const bool value = true; }; -template <> struct is_POD -{ static const bool value = true; }; -} -#else -namespace boost { -template <> struct is_enum -{ enum{ value = true }; }; -template <> struct is_POD -{ enum{ value = true }; }; -// this type is not POD, so we have to specialize the has_* individually -template <> struct has_trivial_constructor -{ enum{ value = true }; }; -template <> struct has_trivial_copy -{ enum{ value = true }; }; -template <> struct has_trivial_assign -{ enum{ value = true }; }; -template <> struct is_POD -{ enum{ value = true }; }; -template <> struct is_union -{ enum{ value = true }; }; -template <> struct is_union -{ enum{ value = true }; }; -template <> struct is_POD -{ enum{ value = true }; }; -template <> struct is_union -{ enum{ value = true }; }; -// this type is not POD, so we have to specialize the has_* individually -template <> struct has_trivial_constructor -{ enum{ value = true }; }; -template <> struct has_trivial_copy -{ enum{ value = true }; }; -template <> struct has_trivial_assign -{ enum{ value = true }; }; -template <> struct is_union -{ enum{ value = true }; }; -template <> struct is_POD -{ enum{ value = true }; }; -} -#endif - -class Base { }; - -class Derived : public Base { }; - -class NonDerived { }; - -enum enum1 -{ - one_,two_ -}; - -enum enum2 -{ - three_,four_ -}; - -struct VB -{ - virtual ~VB(){}; -}; - -struct VD : VB -{ - ~VD(){}; -}; -// -// struct non_pointer: -// used to verify that is_pointer does not return -// true for class types that implement operator void*() -// -struct non_pointer -{ - operator void*(){return this;} -}; -// -// struct non_empty: -// used to verify that is_empty does not emit -// spurious warnings or errors. -// -struct non_empty : boost::noncopyable -{ - int i; -}; - - -struct implicitly_convertible_to_int { - operator int() { return 0; } -}; - - -// Steve: All comments that I (Steve Cleary) have added below are prefixed with -// "Steve:" The failures that BCB4 has on the tests are due to Borland's -// not considering cv-qual's as a part of the type -- they are considered -// compiler hints only. These failures should be fixed before long. - -int main(int, char*[]) -{ - std::cout << "Checking type operations..." << std::endl << std::endl; - - // cv-qualifiers applied to reference types should have no effect - // declare these here for later use with is_reference and remove_reference: - typedef int& r_type; -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable:4181) // qualifier applied to reference type ignored -#endif - typedef const r_type cr_type; -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - - type_test(int, remove_reference::type) - type_test(const int, remove_reference::type) - type_test(int, remove_reference::type) - type_test(const int, remove_reference::type) - type_test(volatile int, remove_reference::type) - type_test(int, remove_reference::type) - - type_test(int, remove_const::type) - // Steve: fails on BCB4 - type_test(volatile int, remove_const::type) - // Steve: fails on BCB4 - type_test(volatile int, remove_const::type) - type_test(int, remove_const::type) - type_test(int*, remove_const::type) - type_test(int, remove_volatile::type) - // Steve: fails on BCB4 - type_test(const int, remove_volatile::type) - // Steve: fails on BCB4 - type_test(const int, remove_volatile::type) - type_test(int, remove_volatile::type) - type_test(int*, remove_volatile::type) - type_test(int, remove_cv::type) - type_test(int, remove_cv::type) - type_test(int, remove_cv::type) - type_test(int, remove_cv::type) - type_test(int*, remove_cv::type) - type_test(int*, remove_cv::type) - type_test(int*, remove_cv::type) - type_test(const int *, remove_cv::type) - type_test(int, remove_bounds::type) - type_test(int*, remove_bounds::type) - type_test(int, remove_bounds::type) - type_test(int[3], remove_bounds::type) - - std::cout << std::endl << "Checking type properties..." << std::endl << std::endl; - - value_test(true, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - value_test(true, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - value_test(false, (is_same::value)) - - value_test(false, is_const::value) - value_test(true, is_const::value) - value_test(false, is_const::value) - value_test(true, is_const::value) - - value_test(false, is_volatile::value) - value_test(false, is_volatile::value) - value_test(true, is_volatile::value) - value_test(true, is_volatile::value) - - value_test(true, is_void::value) - // Steve: fails on BCB4 - // JM: but looks as though it should according to [3.9.3p1]? - //value_test(false, is_void::value) - value_test(false, is_void::value) - - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(true, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(true, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(true, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(true, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - #ifdef ULLONG_MAX - value_test(false, is_standard_unsigned_integral::value) - value_test(false, is_standard_unsigned_integral::value) - #endif - #if defined(__BORLANDC__) || defined(_MSC_VER) - value_test(false, is_standard_unsigned_integral<__int64>::value) - value_test(false, is_standard_unsigned_integral::value) - #endif - - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(true, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(true, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(true, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(true, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - #ifdef ULLONG_MAX - value_test(false, is_standard_signed_integral::value) - value_test(false, is_standard_signed_integral::value) - #endif - #if defined(__BORLANDC__) || defined(_MSC_VER) - value_test(false, is_standard_signed_integral<__int64>::value) - value_test(false, is_standard_signed_integral::value) - #endif - - value_test(false, is_standard_arithmetic::value) - value_test(false, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - value_test(true, is_standard_arithmetic::value) - #ifdef ULLONG_MAX - value_test(false, is_standard_arithmetic::value) - value_test(false, is_standard_arithmetic::value) - #endif - #if defined(__BORLANDC__) || defined(_MSC_VER) - value_test(false, is_standard_arithmetic<__int64>::value) - value_test(false, is_standard_arithmetic::value) - #endif - - value_test(false, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - value_test(true, is_standard_fundamental::value) - #ifdef ULLONG_MAX - value_test(false, is_standard_fundamental::value) - value_test(false, is_standard_fundamental::value) - #endif - #if defined(__BORLANDC__) || defined(_MSC_VER) - value_test(false, is_standard_fundamental<__int64>::value) - value_test(false, is_standard_fundamental::value) - #endif - - value_test(false, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - #ifdef ULLONG_MAX - value_test(true, is_arithmetic::value) - value_test(true, is_arithmetic::value) - #endif - #if defined(__BORLANDC__) || defined(_MSC_VER) - value_test(true, is_arithmetic<__int64>::value) - value_test(true, is_arithmetic::value) - #endif - - value_test(false, is_array::value) - value_test(false, is_array::value) - value_test(false, is_array::value) - value_test(false, is_array::value) - value_test(true, is_array::value) - value_test(true, is_array::value) - value_test(true, is_array::value) - value_test(true, is_array::value) - value_test(true, is_array::value) - value_test(false, is_array::value) - value_test(true, is_array::value) - - typedef void(*f1)(); - typedef int(*f2)(int); - typedef int(*f3)(int, bool); - typedef void (UDT::*mf1)(); - typedef int (UDT::*mf2)(); - typedef int (UDT::*mf3)(int); - typedef int (UDT::*mf4)(int, float); - - value_test(false, is_const::value) - value_test(false, is_reference::value) - value_test(false, is_array::value) - value_test(false, is_pointer::value) - value_test(false, is_pointer::value) - value_test(true, is_pointer::value) - value_test(true, is_pointer::value) - value_test(true, is_pointer::value) - value_test(true, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1 - value_test(false, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1 - value_test(false, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3, 3.9.3p1 - value_test(false, is_pointer::value) - // JM 02 Oct 2000: - value_test(false, is_pointer::value) - value_test(false, is_pointer::value) - value_test(false, is_pointer::value) - value_test(false, is_pointer::value) - value_test(false, is_pointer::value) - - value_test(true, is_pointer::value) - value_test(true, is_pointer::value) - value_test(true, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3 - value_test(false, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3 - value_test(false, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3 - value_test(false, is_pointer::value) - // Steve: was 'true', should be 'false', via 3.9.2p3 - value_test(false, is_pointer::value) - - value_test(false, is_reference::value) - value_test(true, is_reference::value) - value_test(true, is_reference::value) - value_test(true, is_reference::value) - value_test(true, is_reference::value) - value_test(true, is_reference::value) - value_test(true, is_reference::value) - - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(true, is_class::value) - value_test(true, is_class::value) - value_test(true, is_class::value) - value_test(true, is_class::value) - value_test(true, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - value_test(false, is_class::value) - - value_test(true, is_object::value) - value_test(true, is_object::value) - value_test(false, is_object::value) - value_test(false, is_object::value) - value_test(true, is_standard_scalar::value) - value_test(true, is_extension_scalar::value) - - value_test(false, is_enum::value) - value_test(true, is_enum::value) - - value_test(false, is_member_pointer::value) - value_test(false, is_member_pointer::value) - value_test(false, is_member_pointer::value) - value_test(true, is_member_pointer::value) - value_test(true, is_member_pointer::value) - value_test(true, is_member_pointer::value) - value_test(true, is_member_pointer::value) - - value_test(false, is_empty::value) - value_test(false, is_empty::value) - value_test(false, is_empty::value) -#if defined(__MWERKS__) || defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - // apparent compiler bug causes this to fail to compile: - value_fail(false, is_empty::value) -#else - value_test(false, is_empty::value) -#endif -#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - value_fail(false, is_empty::value) -#else - value_test(false, is_empty::value) -#endif - value_test(false, is_empty::value) - value_test(false, is_empty::value) - value_test(true, is_empty::value) - value_test(true, is_empty::value) -#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - value_fail(true, is_empty::value) -#else - value_test(true, is_empty::value) -#endif - value_test(false, is_empty::value) - value_test(true, is_empty::value) - value_test(false, is_empty::value) - - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(false, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - value_test(true, has_trivial_constructor::value) - - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - // Steve: was 'false' -- should be 'true' via 3.9p3, 3.9p10 - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(false, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - value_test(true, has_trivial_copy::value) - - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - // Steve: was 'false' -- should be 'true' via 3.9p3, 3.9p10 - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(false, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - value_test(true, has_trivial_assign::value) - - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - value_test(false, has_trivial_destructor::value) - value_test(false, has_trivial_destructor::value) - value_test(true, has_trivial_destructor::value) - - value_test(true, is_POD::value) - value_test(true, is_POD::value) - // Steve: was 'true', should be 'false', via 3.9p10 - value_test(false, is_POD::value) - value_test(true, is_POD::value) - value_test(true, is_POD::value) - // Steve: was 'false', should be 'true', via 3.9p10 - value_test(true, is_POD::value) - // Steve: was 'true', should be 'false', via 3.9p10 - value_test(false, is_POD::value) - value_test(true, is_POD::value) - value_test(true, is_POD::value) - value_test(true, is_POD::value) - value_test(true, is_POD::value) - value_test(true, is_POD::value) - value_test(false, is_POD::value) - value_test(false, is_POD::value) - value_test(true, is_POD::value) - - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); -#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) - value_test(false, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); -#endif - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - - value_test(false, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(true, (boost::is_convertible::value)); - value_test(false, (boost::is_convertible::value)); - - align_test(int); - align_test(char); - align_test(double); - align_test(int[4]); - align_test(int(*)(int)); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - align_test(char&); - align_test(char (&)(int)); - align_test(char(&)[4]); -#endif - align_test(int*); - //align_test(const int); - align_test(VB); - align_test(VD); - - std::cout << std::endl << test_count << " tests completed (" << failures << " failures)"; - return failures; -} - - - - diff --git a/type_traits_test.hpp b/type_traits_test.hpp deleted file mode 100644 index e86b83e..0000000 --- a/type_traits_test.hpp +++ /dev/null @@ -1,114 +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. - -// common test code for type_traits_test.cpp/call_traits_test.cpp/compressed_pair_test.cpp - - -#ifndef BOOST_TYPE_TRAITS_TEST_HPP -#define BOOST_TYPE_TRAITS_TEST_HPP - -// Variable declarations must come before test_align due to two-phase lookup -unsigned failures = 0; -unsigned test_count = 0; - -// -// this one is here just to suppress warnings: -// -template -bool do_compare(T i, T j) -{ - return i == j; -} - -// -// this one is to verify that a constant is indeed a -// constant-integral-expression: -// -template -struct ct_checker -{ -}; - -#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) -#define BOOST_DO_JOIN2(X, Y) X##Y -#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) - -#ifdef BOOST_MSVC -#define value_test(v, x) ++test_count;\ - {typedef ct_checker<(x)> this_is_a_compile_time_check_;}\ - if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} -#else -#define value_test(v, x) ++test_count;\ - typedef ct_checker<(x)> BOOST_JOIN(this_is_a_compile_time_check_, __LINE__);\ - if(!do_compare((int)v,(int)x)){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} -#endif -#define value_fail(v, x) ++test_count; ++failures; std::cout << "checking value of " << #x << "...failed" << std::endl; - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -#define type_test(v, x) ++test_count;\ - if(do_compare(boost::is_same::value, false)){\ - ++failures; \ - std::cout << "checking type of " << #x << "...failed" << std::endl; \ - std::cout << " expected type was " << #v << std::endl; \ - std::cout << " " << typeid(boost::is_same).name() << "::value is false" << std::endl; } -#else -#define type_test(v, x) ++test_count;\ - if(typeid(v) != typeid(x)){\ - ++failures; \ - std::cout << "checking type of " << #x << "...failed" << std::endl; \ - std::cout << " expected type was " << #v << std::endl; \ - std::cout << " " << "typeid(" #v ") != typeid(" #x ")" << std::endl; } -#endif - -template -struct test_align -{ - struct padded - { - char c; - T t; - }; - static void do_it() - { - padded p; - unsigned a = reinterpret_cast(&(p.t)) - reinterpret_cast(&p); - value_test(a, boost::alignment_of::value); - } -}; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -template -struct test_align -{ - static void do_it() - { - // - // we can't do the usual test because we can't take the address - // of a reference, so check that the result is the same as for a - // pointer type instead: - value_test(boost::alignment_of::value, boost::alignment_of::value); - } -}; -#endif - -#define align_test(T) test_align::do_it() - -// -// define tests here - -// -// turn off some warnings: -#ifdef __BORLANDC__ -#pragma option -w-8004 -#endif - -#ifdef BOOST_MSVC -#pragma warning (disable: 4018) -#endif - - -#endif // BOOST_TYPE_TRAITS_TEST_HPP -