From 06adfe9658d30b448a52aa950b5125a61c0d0002 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 7 Jul 2000 16:04:40 +0000 Subject: [PATCH 01/12] This commit was generated by cvs2svn to compensate for changes in r4, which included commits to RCS files with non-trunk default branches. [SVN r7621] --- .gitattributes | 96 +++ algo_opt_examples.cpp | 406 +++++++++++++ call_traits_test.cpp | 208 +++++++ cast_test.cpp | 149 +++++ include/boost/call_traits.hpp | 23 + include/boost/compressed_pair.hpp | 23 + include/boost/detail/call_traits.hpp | 97 +++ include/boost/detail/compressed_pair.hpp | 420 +++++++++++++ include/boost/detail/ob_call_traits.hpp | 35 ++ include/boost/detail/ob_compressed_pair.hpp | 69 +++ include/boost/operators.hpp | 559 ++++++++++++++++++ include/boost/utility.hpp | 69 +++ iterators_test.cpp | 169 ++++++ noncopyable_test.cpp | 38 ++ operators_test.cpp | 481 +++++++++++++++ type_traits_test.cpp | 623 ++++++++++++++++++++ 16 files changed, 3465 insertions(+) create mode 100644 .gitattributes create mode 100644 algo_opt_examples.cpp create mode 100644 call_traits_test.cpp create mode 100644 cast_test.cpp create mode 100644 include/boost/call_traits.hpp create mode 100644 include/boost/compressed_pair.hpp create mode 100644 include/boost/detail/call_traits.hpp create mode 100644 include/boost/detail/compressed_pair.hpp create mode 100644 include/boost/detail/ob_call_traits.hpp create mode 100644 include/boost/detail/ob_compressed_pair.hpp create mode 100644 include/boost/operators.hpp create mode 100644 include/boost/utility.hpp create mode 100644 iterators_test.cpp create mode 100644 noncopyable_test.cpp create mode 100644 operators_test.cpp create mode 100644 type_traits_test.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/algo_opt_examples.cpp b/algo_opt_examples.cpp new file mode 100644 index 0000000..6b795e7 --- /dev/null +++ b/algo_opt_examples.cpp @@ -0,0 +1,406 @@ + +/* + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using std::cout; +using std::endl; +using std::cin; + +namespace opt{ + +// +// algorithm destroy_arry: +// 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) + { + 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; + } +}; + +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 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; + + 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; + + // + // 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/call_traits_test.cpp b/call_traits_test.cpp new file mode 100644 index 0000000..c615013 --- /dev/null +++ b/call_traits_test.cpp @@ -0,0 +1,208 @@ + +#include +#include +#include +#include +#include +#include + +// +// struct contained models a type that contains a type (for example std::pair) +// arrays are contained by value, and have to be treated as a special case: +// +template +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::param_type param_type; + typedef typename boost::call_traits::reference reference; + typedef typename boost::call_traits::const_reference const_reference; + typedef T value_type; + typedef typename boost::call_traits::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){} + +}; + +template +struct contained +{ + typedef typename boost::call_traits::param_type param_type; + typedef typename boost::call_traits::reference reference; + typedef typename boost::call_traits::const_reference const_reference; + typedef T value_type[N]; + typedef typename boost::call_traits::value_type result_type; + + value_type v_; + + contained(param_type p) + { + std::copy(p, p+N, v_); + } + // return byval: + result_type value() { return v_; } + // return by_ref: + reference get() { return v_; } + const_reference const_get()const { return v_; } + void call(param_type p){} +}; + +template +contained::value_type> wrap(const T& t) +{ + return contained::value_type>(t); +} + +template +std::pair< + typename boost::call_traits::value_type, + typename boost::call_traits::value_type> + make_pair(const T1& t1, const T2& t2) +{ + return std::pair< + typename boost::call_traits::value_type, + typename boost::call_traits::value_type>(t1, t2); +} + +using namespace std; + +// +// struct checker: +// verifies behaviour of contained example: +// +template +struct checker +{ + typedef typename boost::call_traits::param_type param_type; + void operator()(param_type); +}; + +template +void checker::operator()(param_type p) +{ + T t(p); + contained c(t); + cout << "checking contained<" << typeid(T).name() << ">..." << endl; + assert(t == c.value()); + assert(t == c.get()); + assert(t == c.const_get()); + + cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained::value).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained::get).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained::const_get).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::call() is: " << typeid(&contained::call).name() << endl; + cout << endl; +} + +template +struct checker +{ + typedef typename boost::call_traits::param_type param_type; + void operator()(param_type); +}; + +template +void checker::operator()(param_type t) +{ + contained c(t); + cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl; + unsigned int i = 0; + for(i = 0; i < N; ++i) + assert(t[i] == c.value()[i]); + for(i = 0; i < N; ++i) + assert(t[i] == c.get()[i]); + for(i = 0; i < N; ++i) + assert(t[i] == c.const_get()[i]); + + cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained::value).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained::get).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained::const_get).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained::call).name() << endl; + cout << endl; +} + +// +// check_wrap: +// verifies behaviour of "wrap": +// +template +void check_wrap(T c, U u, const V& v) +{ + cout << "checking contained<" << typeid(T::value_type).name() << ">..." << endl; + assert(c.get() == u); + cout << "typeof deduced argument was: " << typeid(V).name() << endl; + cout << "typeof deduced parameter after adjustment was: " << typeid(v).name() << endl; + cout << "typeof contained<" << typeid(T::value_type).name() << ">::v_ is: " << typeid(&T::v_).name() << endl; + cout << "typeof contained<" << typeid(T::value_type).name() << ">::value is: " << typeid(&T::value).name() << endl; + cout << "typeof contained<" << typeid(T::value_type).name() << ">::get is: " << typeid(&T::get).name() << endl; + cout << "typeof contained<" << typeid(T::value_type).name() << ">::const_get is: " << typeid(&T::const_get).name() << endl; + cout << "typeof contained<" << typeid(T::value_type).name() << ">::call is: " << typeid(&T::call).name() << endl; + cout << endl; +} + +// +// check_make_pair: +// verifies behaviour of "make_pair": +// +template +void check_make_pair(T c, U u, V v) +{ + cout << "checking std::pair<" << typeid(c.first).name() << ", " << typeid(c.second).name() << ">..." << endl; + assert(c.first == u); + assert(c.second == v); + cout << endl; +} + + +struct UDT +{ + int i_; + UDT() : i_(2){} + bool operator == (const UDT& v){ return v.i_ == i_; } +}; + + +int main() +{ + checker c1; + UDT u; + c1(u); + checker c2; + int i = 2; + c2(i); + int* pi = &i; + checker c3; + c3(pi); + checker c4; + c4(i); + checker c5; + c5(i); + + int a[2] = {1,2}; + checker c6; + c6(a); + + check_wrap(wrap(2), 2, 2); + const char ca[4] = "abc"; + // compiler can't deduce this for some reason: + //check_wrap(wrap(ca), ca, ca); + check_wrap(wrap(a), a, a); + check_make_pair(::make_pair(a, a), a, a); + + return 0; +} diff --git a/cast_test.cpp b/cast_test.cpp new file mode 100644 index 0000000..66ff462 --- /dev/null +++ b/cast_test.cpp @@ -0,0 +1,149 @@ +// boost utility cast test program -----------------------------------------// + +// (C) Copyright boost.org 1999. 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. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 28 Jun 00 implicit_cast removed (Beman Dawes) +// 30 Aug 99 value_cast replaced by numeric_cast +// 3 Aug 99 Initial Version + +#include +#include +#include +#include + +# if SCHAR_MAX == LONG_MAX +# error "This test program doesn't work if SCHAR_MAX == LONG_MAX" +# endif + +using namespace boost; +using std::cout; + +namespace +{ + struct Base + { + virtual char kind() { return 'B'; } + }; + + struct Base2 + { + virtual char kind2() { return '2'; } + }; + + struct Derived : public Base, Base2 + { + virtual char kind() { return 'D'; } + }; +} + + +int main( int argc, char * argv[] ) +{ + cout << "Usage: test_casts [n], where n omitted or is:\n" + " 1 = execute #1 assert failure (#ifndef NDEBUG)\n" + " 2 = execute #2 assert failure (#ifndef NDEBUG)\n" + "Example: test_casts 2\n\n"; + +# ifdef NDEBUG + cout << "NDEBUG is defined\n"; +# else + cout << "NDEBUG is not defined\n"; +# endif + + cout << "\nBeginning tests...\n"; + +// test polymorphic_cast ---------------------------------------------------// + + // tests which should succeed + Base * base = new Derived; + Base2 * base2 = 0; + Derived * derived = 0; + derived = polymorphic_downcast( base ); // downcast + assert( derived->kind() == 'D' ); + + derived = 0; + derived = polymorphic_cast( base ); // downcast, throw on error + assert( derived->kind() == 'D' ); + + base2 = polymorphic_cast( base ); // crosscast + assert( base2->kind2() == '2' ); + + // tests which should result in errors being detected + int err_count = 0; + base = new Base; + + if ( argc > 1 && *argv[1] == '1' ) + { derived = polymorphic_downcast( base ); } // #1 assert failure + + bool caught_exception = false; + try { derived = polymorphic_cast( base ); } + catch (std::bad_cast) + { cout<<"caught bad_cast\n"; caught_exception = true; } + if ( !caught_exception ) ++err_count; + // the following is just so generated code can be inspected + if ( derived->kind() == 'B' ) ++err_count; + +// test implicit_cast and numeric_cast -------------------------------------// + + // tests which should succeed + long small_value = 1; + long small_negative_value = -1; + long large_value = std::numeric_limits::max(); + long large_negative_value = std::numeric_limits::min(); + signed char c = 0; + + c = large_value; // see if compiler generates warning + + c = numeric_cast( small_value ); + assert( c == 1 ); + c = 0; + c = numeric_cast( small_value ); + assert( c == 1 ); + c = 0; + c = numeric_cast( small_negative_value ); + assert( c == -1 ); + + // tests which should result in errors being detected + + caught_exception = false; + try { c = numeric_cast( large_value ); } + catch (bad_numeric_cast) + { cout<<"caught bad_numeric_cast #1\n"; caught_exception = true; } + if ( !caught_exception ) ++err_count; + + caught_exception = false; + try { c = numeric_cast( large_negative_value ); } + catch (bad_numeric_cast) + { cout<<"caught bad_numeric_cast #2\n"; caught_exception = true; } + if ( !caught_exception ) ++err_count; + + unsigned long ul; + caught_exception = false; + try { ul = numeric_cast( large_negative_value ); } + catch (bad_numeric_cast) + { cout<<"caught bad_numeric_cast #3\n"; caught_exception = true; } + if ( !caught_exception ) ++err_count; + + caught_exception = false; + try { ul = numeric_cast( small_negative_value ); } + catch (bad_numeric_cast) + { cout<<"caught bad_numeric_cast #4\n"; caught_exception = true; } + if ( !caught_exception ) ++err_count; + + caught_exception = false; + try { numeric_cast( std::numeric_limits::max() ); } + catch (bad_numeric_cast) + { cout<<"caught bad_numeric_cast #5\n"; caught_exception = true; } + if ( !caught_exception ) ++err_count; + + cout << err_count << " errors detected\nTest " + << (err_count==0 ? "passed\n" : "failed\n"); + return err_count; +} // main diff --git a/include/boost/call_traits.hpp b/include/boost/call_traits.hpp new file mode 100644 index 0000000..345a440 --- /dev/null +++ b/include/boost/call_traits.hpp @@ -0,0 +1,23 @@ +// (C) Copyright Boost.org 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. + +// See http://www.boost.org for most recent version including documentation. +// See boost/detail/call_traits.hpp and boost/detail/ob_call_traits.hpp +// for full copyright notices. + +#ifndef BOOST_CALL_TRAITS_HPP +#define BOOST_CALL_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#include +#else +#include +#endif + +#endif // BOOST_CALL_TRAITS_HPP diff --git a/include/boost/compressed_pair.hpp b/include/boost/compressed_pair.hpp new file mode 100644 index 0000000..c55ca2d --- /dev/null +++ b/include/boost/compressed_pair.hpp @@ -0,0 +1,23 @@ +// (C) Copyright Boost.org 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. + +// See http://www.boost.org for most recent version including documentation. +// See boost/detail/compressed_pair.hpp and boost/detail/ob_compressed_pair.hpp +// for full copyright notices. + +#ifndef BOOST_COMPRESSED_PAIR_HPP +#define BOOST_COMPRESSED_PAIR_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#include +#else +#include +#endif + +#endif // BOOST_COMPRESSED_PAIR_HPP diff --git a/include/boost/detail/call_traits.hpp b/include/boost/detail/call_traits.hpp new file mode 100644 index 0000000..07ed4ec --- /dev/null +++ b/include/boost/detail/call_traits.hpp @@ -0,0 +1,97 @@ +// (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. + +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_DETAIL_CALL_TRAITS_HPP +#define BOOST_DETAIL_CALL_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#ifndef BOOST_TYPE_TRAITS_HPP +#include +#endif + +namespace boost{ + +namespace detail{ + +template +struct ct_imp +{ + typedef const T& param_type; +}; + +template +struct ct_imp +{ + typedef T const param_type; +}; + +template +struct ct_imp +{ + typedef T const param_type; +}; + +} + +template +struct call_traits +{ +public: + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + // + // C++ Builder workaround: we should be able to define a compile time + // constant and pass that as a single template parameter to ct_imp, + // however compiler bugs prevent this - instead pass three bool's to + // ct_imp and add an extra partial specialisation + // of ct_imp to handle the logic. (JM) + typedef typename detail::ct_imp::type>::value, ::boost::is_arithmetic::type>::value, sizeof(T) <= sizeof(void*)>::param_type param_type; +}; + +template +struct call_traits +{ + typedef T& value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T& param_type; // hh removed const +}; + +template +struct call_traits +{ +private: + typedef T array_type[N]; +public: + // degrades array to pointer: + typedef const T* value_type; + typedef array_type& reference; + typedef const array_type& const_reference; + typedef const T* param_type; +}; + +template +struct call_traits +{ +private: + typedef const T array_type[N]; +public: + // degrades array to pointer: + typedef const T* value_type; + typedef array_type& reference; + typedef const array_type& const_reference; + typedef const T* param_type; +}; + +} + +#endif // BOOST_DETAIL_CALL_TRAITS_HPP diff --git a/include/boost/detail/compressed_pair.hpp b/include/boost/detail/compressed_pair.hpp new file mode 100644 index 0000000..a4b3390 --- /dev/null +++ b/include/boost/detail/compressed_pair.hpp @@ -0,0 +1,420 @@ +// (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. + +// See http://www.boost.org for most recent version including documentation. + +// +// JM changes 25 Jan 2000: +// Removed default arguments from compressed_pair_switch to get +// C++ Builder 4 to accept them +// rewriten swap to get gcc and C++ builder to compile. +// added partial specialisations for case T1 == T2 to avoid duplicate constructor defs. + +#ifndef BOOST_DETAIL_COMPRESSED_PAIR_HPP +#define BOOST_DETAIL_COMPRESSED_PAIR_HPP + +#include +#ifndef BOOST_TYPE_TRAITS_HPP +#include +#endif +#ifndef BOOST_CALL_TRAITS_HPP +#include +#endif + +namespace boost +{ + +// compressed_pair + +namespace details +{ + // JM altered 26 Jan 2000: + template + struct compressed_pair_switch; + + template + struct compressed_pair_switch + {static const int value = 0;}; + + template + struct compressed_pair_switch + {static const int value = 3;}; + + template + struct compressed_pair_switch + {static const int value = 1;}; + + template + struct compressed_pair_switch + {static const int value = 2;}; + + template + struct compressed_pair_switch + {static const int value = 4;}; + + template + struct compressed_pair_switch + {static const int value = 5;}; + + template class compressed_pair_imp; + +#ifdef __GNUC__ + // workaround for GCC (JM): + using std::swap; +#endif + // + // can't call unqualified swap from within classname::swap + // as Koenig lookup rules will find only the classname::swap + // member function not the global declaration, so use cp_swap + // as a forwarding function (JM): + template + inline void cp_swap(T& t1, T& t2) + { + using std::swap; + swap(t1, t2); + } + + // 0 derive from neither + + template + class compressed_pair_imp + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : first_(x), second_(y) {} + + explicit compressed_pair_imp(first_param_type x) + : first_(x) {} + + explicit compressed_pair_imp(second_param_type y) + : second_(y) {} + + first_reference first() {return first_;} + first_const_reference first() const {return first_;} + + second_reference second() {return second_;} + second_const_reference second() const {return second_;} + + void swap(compressed_pair_imp& y) + { + cp_swap(first_, y.first_); + cp_swap(second_, y.second_); + } + private: + first_type first_; + second_type second_; + }; + + // 1 derive from T1 + + template + class compressed_pair_imp + : private T1 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : first_type(x), second_(y) {} + + explicit compressed_pair_imp(first_param_type x) + : first_type(x) {} + + explicit compressed_pair_imp(second_param_type y) + : second_(y) {} + + first_reference first() {return *this;} + first_const_reference first() const {return *this;} + + second_reference second() {return second_;} + second_const_reference second() const {return second_;} + + void swap(compressed_pair_imp& y) + { + // no need to swap empty base class: + cp_swap(second_, y.second_); + } + private: + second_type second_; + }; + + // 2 derive from T2 + + template + class compressed_pair_imp + : private T2 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : second_type(y), first_(x) {} + + explicit compressed_pair_imp(first_param_type x) + : first_(x) {} + + explicit compressed_pair_imp(second_param_type y) + : second_type(y) {} + + first_reference first() {return first_;} + first_const_reference first() const {return first_;} + + second_reference second() {return *this;} + second_const_reference second() const {return *this;} + + void swap(compressed_pair_imp& y) + { + // no need to swap empty base class: + cp_swap(first_, y.first_); + } + + private: + first_type first_; + }; + + // 3 derive from T1 and T2 + + template + class compressed_pair_imp + : private T1, + private T2 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : first_type(x), second_type(y) {} + + explicit compressed_pair_imp(first_param_type x) + : first_type(x) {} + + explicit compressed_pair_imp(second_param_type y) + : second_type(y) {} + + first_reference first() {return *this;} + first_const_reference first() const {return *this;} + + second_reference second() {return *this;} + second_const_reference second() const {return *this;} + // + // no need to swap empty bases: + void swap(compressed_pair_imp&) {} + }; + + // JM + // 4 T1 == T2, T1 and T2 both empty + // Note does not actually store an instance of T2 at all - + // but reuses T1 base class for both first() and second(). + template + class compressed_pair_imp + : private T1 + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type) + : first_type(x) {} + + explicit compressed_pair_imp(first_param_type x) + : first_type(x) {} + + first_reference first() {return *this;} + first_const_reference first() const {return *this;} + + second_reference second() {return *this;} + second_const_reference second() const {return *this;} + + void swap(compressed_pair_imp&) {} + private: + }; + + // 5 T1 == T2 and are not empty: //JM + + template + class compressed_pair_imp + { + public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair_imp() {} + + compressed_pair_imp(first_param_type x, second_param_type y) + : first_(x), second_(y) {} + + explicit compressed_pair_imp(first_param_type x) + : first_(x), second_(x) {} + + first_reference first() {return first_;} + first_const_reference first() const {return first_;} + + second_reference second() {return second_;} + second_const_reference second() const {return second_;} + + void swap(compressed_pair_imp& y) + { + cp_swap(first_, y.first_); + cp_swap(second_, y.second_); + } + private: + first_type first_; + second_type second_; + }; + +} // details + +template +class compressed_pair + : private ::boost::details::compressed_pair_imp::type, typename remove_cv::type>::value, + ::boost::is_empty::value, + ::boost::is_empty::value>::value> +{ +private: + typedef details::compressed_pair_imp::type, typename remove_cv::type>::value, + ::boost::is_empty::value, + ::boost::is_empty::value>::value> base; +public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair() : base() {} + compressed_pair(first_param_type x, second_param_type y) : base(x, y) {} + explicit compressed_pair(first_param_type x) : base(x) {} + explicit compressed_pair(second_param_type y) : base(y) {} + + first_reference first() {return base::first();} + first_const_reference first() const {return base::first();} + + second_reference second() {return base::second();} + second_const_reference second() const {return base::second();} + + void swap(compressed_pair& y) { base::swap(y); } +}; + +// JM +// Partial specialisation for case where T1 == T2: +// +template +class compressed_pair + : private details::compressed_pair_imp::type, typename remove_cv::type>::value, + ::boost::is_empty::value, + ::boost::is_empty::value>::value> +{ +private: + typedef details::compressed_pair_imp::type, typename remove_cv::type>::value, + ::boost::is_empty::value, + ::boost::is_empty::value>::value> base; +public: + typedef T first_type; + typedef T second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair() : base() {} + compressed_pair(first_param_type x, second_param_type y) : base(x, y) {} + explicit compressed_pair(first_param_type x) : base(x) {} + + first_reference first() {return base::first();} + first_const_reference first() const {return base::first();} + + second_reference second() {return base::second();} + second_const_reference second() const {return base::second();} + + void swap(compressed_pair& y) { base::swap(y); } +}; + +template +inline +void +swap(compressed_pair& x, compressed_pair& y) +{ + x.swap(y); +} + +} // boost + +#endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP + + diff --git a/include/boost/detail/ob_call_traits.hpp b/include/boost/detail/ob_call_traits.hpp new file mode 100644 index 0000000..332931e --- /dev/null +++ b/include/boost/detail/ob_call_traits.hpp @@ -0,0 +1,35 @@ +// (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. + +// See http://www.boost.org for most recent version including documentation. +// +// Crippled version for crippled compilers: +// +#ifndef BOOST_OB_CALL_TRAITS_HPP +#define BOOST_OB_CALL_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#ifndef BOOST_TYPE_TRAITS_HPP +#include +#endif + +namespace boost{ + +template +struct call_traits +{ + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + typedef const T& param_type; +}; + +} + +#endif // BOOST_OB_CALL_TRAITS_HPP diff --git a/include/boost/detail/ob_compressed_pair.hpp b/include/boost/detail/ob_compressed_pair.hpp new file mode 100644 index 0000000..f5f5664 --- /dev/null +++ b/include/boost/detail/ob_compressed_pair.hpp @@ -0,0 +1,69 @@ +// (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. + +// See http://www.boost.org for most recent version including documentation. +// +// this version crippled for use with crippled compilers - John Maddock Jan 2000. + +#ifndef BOOST_OB_COMPRESSED_PAIR_HPP +#define BOOST_OB_COMPRESSED_PAIR_HPP + +#include +#ifndef BOOST_TYPE_TRAITS_HPP +#include +#endif +#ifndef BOOST_CALL_TRAITS_HPP +#include +#endif + +namespace boost +{ + +template +class compressed_pair +{ +private: + T1 _first; + T2 _second; +public: + typedef T1 first_type; + typedef T2 second_type; + typedef typename call_traits::param_type first_param_type; + typedef typename call_traits::param_type second_param_type; + typedef typename call_traits::reference first_reference; + typedef typename call_traits::reference second_reference; + typedef typename call_traits::const_reference first_const_reference; + typedef typename call_traits::const_reference second_const_reference; + + compressed_pair() : _first(), _second() {} + compressed_pair(first_param_type x, second_param_type y) : _first(x), _second(y) {} + explicit compressed_pair(first_param_type x) : _first(x), _second() {} + //explicit compressed_pair(second_param_type y) : _first(), _second(y) {} + + first_reference first() { return _first; } + first_const_reference first() const { return _first; } + + second_reference second() { return _second; } + second_const_reference second() const { return _second; } + + void swap(compressed_pair& y) + { + using std::swap; + swap(_first, y._first); + swap(_second, y._second); + } +}; + +template +inline void swap(compressed_pair& x, compressed_pair& y) +{ + x.swap(y); +} + +} // boost + +#endif // BOOST_OB_COMPRESSED_PAIR_HPP + diff --git a/include/boost/operators.hpp b/include/boost/operators.hpp new file mode 100644 index 0000000..8144c7c --- /dev/null +++ b/include/boost/operators.hpp @@ -0,0 +1,559 @@ +// Boost operators.hpp header file ----------------------------------------// + +// (C) Copyright David Abrahams 1999. 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. + +// (C) Copyright Jeremy Siek 1999. 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. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 04 Jul 00 Fixed NO_OPERATORS_IN_NAMESPACE bugs, major cleanup and +// refactoring of compiler workarounds, additional documentation +// (Alexy Gurtovoy and Mark Rodgers with some help and prompting from +// Dave Abrahams) +// 28 Jun 00 General cleanup and integration of bugfixes from Mark Rodgers and +// Jeremy Siek (Dave Abrahams) +// 20 Jun 00 Changes to accommodate Borland C++Builder 4 and Borland C++ 5.5 +// (Mark Rodgers) +// 20 Jun 00 Minor fixes to the prior revision (Aleksey Gurtovoy) +// 10 Jun 00 Support for the base class chaining technique was added +// (Aleksey Gurtovoy). See documentation and the comments below +// for the details. +// 12 Dec 99 Initial version with iterator operators (Jeremy Siek) +// 18 Nov 99 Change name "divideable" to "dividable", remove unnecessary +// specializations of dividable, subtractable, modable (Ed Brey) +// 17 Nov 99 Add comments (Beman Dawes) +// Remove unnecessary specialization of operators<> (Ed Brey) +// 15 Nov 99 Fix less_than_comparable second operand type for first two +// operators.(Beman Dawes) +// 12 Nov 99 Add operators templates (Ed Brey) +// 11 Nov 99 Add single template parameter version for compilers without +// partial specialization (Beman Dawes) +// 10 Nov 99 Initial version + +// 10 Jun 00: +// An additional optional template parameter was added to most of +// operator templates to support the base class chaining technique (see +// documentation for the details). Unfortunately, a straightforward +// implementation of this change would have broken compatibility with the +// previous version of the library by making it impossible to use the same +// template name (e.g. 'addable') for both the 1- and 2-argument versions of +// an operator template. This implementation solves the backward-compatibility +// issue at the cost of some simplicity. +// +// One of the complications is an existence of special auxiliary class template +// 'is_chained_base<>' (see 'detail' namespace below), which is used +// to determine whether its template parameter is a library's operator template +// or not. You have to specialize 'is_chained_base<>' for each new +// operator template you add to the library. +// +// However, most of the non-trivial implementation details are hidden behind +// several local macros defined below, and as soon as you understand them, +// you understand the whole library implementation. + +#ifndef BOOST_OPERATORS_HPP +#define BOOST_OPERATORS_HPP + +#include +#include + +#if defined(__sgi) && !defined(__GNUC__) +#pragma set woff 1234 +#endif + +namespace boost { +namespace detail { + +class empty_base {}; + +} // namespace detail +} // namespace boost + +// In this section we supply the xxxx1 and xxxx2 forms of the operator +// templates, which are explicitly targeted at the 1-type-argument and +// 2-type-argument operator forms, respectively. Some compilers get confused +// when inline friend functions are overloaded in namespaces other than the +// global namespace. When BOOST_NO_OPERATORS_IN_NAMESPACE is defined, all of +// these templates must go in the global namespace. + +#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE +namespace boost +{ +#endif + +// Basic operator classes (contributed by Dave Abrahams) ------------------// + +// Note that friend functions defined in a class are implicitly inline. +// See the C++ std, 11.4 [class.friend] paragraph 5 + +template +struct less_than_comparable2 : B +{ + friend bool operator<=(const T& x, const U& y) { return !(x > y); } + friend bool operator>=(const T& x, const U& y) { return !(x < y); } + friend bool operator>(const U& x, const T& y) { return y < x; } + friend bool operator<(const U& x, const T& y) { return y > x; } + friend bool operator<=(const U& x, const T& y) { return !(y < x); } + friend bool operator>=(const U& x, const T& y) { return !(y > x); } +}; + +template +struct less_than_comparable1 : B +{ + friend bool operator>(const T& x, const T& y) { return y < x; } + friend bool operator<=(const T& x, const T& y) { return !(y < x); } + friend bool operator>=(const T& x, const T& y) { return !(x < y); } +}; + +template +struct equality_comparable2 : B +{ + friend bool operator==(const U& y, const T& x) { return x == y; } + friend bool operator!=(const U& y, const T& x) { return !(x == y); } + friend bool operator!=(const T& y, const U& x) { return !(y == x); } +}; + +template +struct equality_comparable1 : B +{ + friend bool operator!=(const T& x, const T& y) { return !(x == y); } +}; + +template +struct multipliable2 : B +{ + friend T operator*(T x, const U& y) { return x *= y; } + friend T operator*(const U& y, T x) { return x *= y; } +}; + +template +struct multipliable1 : B +{ + friend T operator*(T x, const T& y) { return x *= y; } +}; + +template +struct addable2 : B +{ + friend T operator+(T x, const U& y) { return x += y; } + friend T operator+(const U& y, T x) { return x += y; } +}; + +template +struct addable1 : B +{ + friend T operator+(T x, const T& y) { return x += y; } +}; + +template +struct subtractable2 : B +{ + friend T operator-(T x, const U& y) { return x -= y; } +}; + +template +struct subtractable1 : B +{ + friend T operator-(T x, const T& y) { return x -= y; } +}; + +template +struct dividable2 : B +{ + friend T operator/(T x, const U& y) { return x /= y; } +}; + +template +struct dividable1 : B +{ + friend T operator/(T x, const T& y) { return x /= y; } +}; + +template +struct modable2 : B +{ + friend T operator%(T x, const U& y) { return x %= y; } +}; + +template +struct modable1 : B +{ + friend T operator%(T x, const T& y) { return x %= y; } +}; + +template +struct xorable2 : B +{ + friend T operator^(T x, const U& y) { return x ^= y; } + friend T operator^(const U& y, T x) { return x ^= y; } +}; + +template +struct xorable1 : B +{ + friend T operator^(T x, const T& y) { return x ^= y; } +}; + +template +struct andable2 : B +{ + friend T operator&(T x, const U& y) { return x &= y; } + friend T operator&(const U& y, T x) { return x &= y; } +}; + +template +struct andable1 : B +{ + friend T operator&(T x, const T& y) { return x &= y; } +}; + +template +struct orable2 : B +{ + friend T operator|(T x, const U& y) { return x |= y; } + friend T operator|(const U& y, T x) { return x |= y; } +}; + +template +struct orable1 : B +{ + friend T operator|(T x, const T& y) { return x |= y; } +}; + +// incrementable and decrementable contributed by Jeremy Siek + +template +struct incrementable : B +{ + friend T operator++(T& x, int) + { + incrementable_type tmp(x); + ++x; + return tmp; + } +private: // The use of this typedef works around a Borland bug + typedef T incrementable_type; +}; + +template +struct decrementable : B +{ + friend T operator--(T& x, int) + { + decrementable_type tmp(x); + --x; + return tmp; + } +private: // The use of this typedef works around a Borland bug + typedef T decrementable_type; +}; + +// Iterator operator classes (contributed by Jeremy Siek) ------------------// + +template +struct dereferenceable : B +{ + P operator->() const + { + return &*static_cast(*this); + } +}; + +template +struct indexable : B +{ + R operator[](I n) const + { + return *(static_cast(*this) + n); + } +}; + +#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE +} // namespace boost +#endif // BOOST_NO_OPERATORS_IN_NAMESPACE + + +// BOOST_IMPORT_TEMPLATE1/BOOST_IMPORT_TEMPLATE2 - +// +// When BOOST_NO_OPERATORS_IN_NAMESPACE is defined we need a way to import an +// operator template into the boost namespace. BOOST_IMPORT_TEMPLATE1 is used +// for one-argument forms of operator templates; BOOST_IMPORT_TEMPLATE2 for +// two-argument forms. Note that these macros expect to be invoked from within +// boost. + +#if defined(BOOST_NO_OPERATORS_IN_NAMESPACE) + +# if defined(BOOST_NO_USING_TEMPLATE) + + // Because a Borland C++ 5.5 bug prevents a using declaration from working, + // we are forced to use inheritance for that compiler. +# define BOOST_IMPORT_TEMPLATE2(template_name) \ + template \ + struct template_name : ::template_name {}; + +# define BOOST_IMPORT_TEMPLATE1(template_name) \ + template \ + struct template_name : ::template_name {}; + +# else + + // Otherwise, bring the names in with a using-declaration to avoid + // stressing the compiler +# define BOOST_IMPORT_TEMPLATE2(template_name) using ::template_name; +# define BOOST_IMPORT_TEMPLATE1(template_name) using ::template_name; + +# endif // BOOST_NO_USING_TEMPLATE + +#else // !BOOST_NO_OPERATORS_IN_NAMESPACE + + // The template is already in boost so we have nothing to do. +# define BOOST_IMPORT_TEMPLATE2(template_name) +# define BOOST_IMPORT_TEMPLATE1(template_name) + +#endif // BOOST_NO_OPERATORS_IN_NAMESPACE + +// +// Here's where we put it all together, defining the xxxx forms of the templates +// in namespace boost. We also define specializations of is_chained_base<> for +// the xxxx, xxxx1, and xxxx2 templates, importing them into boost:: as +// neccessary. +// +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +// is_chained_base<> - a traits class used to distinguish whether an operator +// template argument is being used for base class chaining, or is specifying a +// 2nd argument type. + +namespace boost { +// A type parameter is used instead of a plain bool because Borland's compiler +// didn't cope well with the more obvious non-type template parameter. +namespace detail { + struct true_t {}; + struct false_t {}; +} // namespace detail + +// Unspecialized version assumes that most types are not being used for base +// class chaining. We specialize for the operator templates defined in this +// library. +template struct is_chained_base { + typedef ::boost::detail::false_t value; +}; + +} // namespace boost + +// Import a 2-type-argument operator template into boost (if neccessary) and +// provide a specialization of 'is_chained_base<>' for it. +# define BOOST_OPERATOR_TEMPLATE2(template_name2) \ + BOOST_IMPORT_TEMPLATE2(template_name2) \ + template \ + struct is_chained_base< ::boost::template_name2 > { \ + typedef ::boost::detail::true_t value; \ + }; + +// Import a 1-type-argument operator template into boost (if neccessary) and +// provide a specialization of 'is_chained_base<>' for it. +# define BOOST_OPERATOR_TEMPLATE1(template_name1) \ + BOOST_IMPORT_TEMPLATE1(template_name1) \ + template \ + struct is_chained_base< ::boost::template_name1 > { \ + typedef ::boost::detail::true_t value; \ + }; + +// BOOST_OPERATOR_TEMPLATE(template_name) defines template_name<> such that it +// can be used for specifying both 1-argument and 2-argument forms. Requires the +// existence of two previously defined class templates named '1' +// and '2' which must implement the corresponding 1- and 2- +// argument forms. +// +// The template type parameter O == is_chained_base::value is used to +// distinguish whether the 2nd argument to is being used for +// base class chaining from another boost operator template or is describing a +// 2nd operand type. O == true_t only when U is actually an another operator +// template from the library. Partial specialization is used to select an +// implementation in terms of either '1' or '2'. +// + +# define BOOST_OPERATOR_TEMPLATE(template_name) \ +template ::value \ + > \ +struct template_name : template_name##2 {}; \ + \ +template \ +struct template_name \ + : template_name##1 {}; \ + \ +template \ +struct template_name \ + : template_name##1 {}; \ + \ +template \ +struct is_chained_base< ::boost::template_name > { \ + typedef ::boost::detail::true_t value; \ +}; \ + \ +BOOST_OPERATOR_TEMPLATE2(template_name##2) \ +BOOST_OPERATOR_TEMPLATE1(template_name##1) + + +#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +# define BOOST_OPERATOR_TEMPLATE2(template_name2) \ + BOOST_IMPORT_TEMPLATE2(template_name2) +# define BOOST_OPERATOR_TEMPLATE1(template_name1) \ + BOOST_IMPORT_TEMPLATE1(template_name1) + + // In this case we can only assume that template_name<> is equivalent to the + // more commonly needed template_name1<> form. +# define BOOST_OPERATOR_TEMPLATE(template_name) \ + template \ + struct template_name : template_name##1 {}; + +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +namespace boost { + +BOOST_OPERATOR_TEMPLATE(less_than_comparable) +BOOST_OPERATOR_TEMPLATE(equality_comparable) +BOOST_OPERATOR_TEMPLATE(multipliable) +BOOST_OPERATOR_TEMPLATE(addable) +BOOST_OPERATOR_TEMPLATE(subtractable) +BOOST_OPERATOR_TEMPLATE(dividable) +BOOST_OPERATOR_TEMPLATE(modable) +BOOST_OPERATOR_TEMPLATE(xorable) +BOOST_OPERATOR_TEMPLATE(andable) +BOOST_OPERATOR_TEMPLATE(orable) + +BOOST_OPERATOR_TEMPLATE1(incrementable) +BOOST_OPERATOR_TEMPLATE1(decrementable) +BOOST_OPERATOR_TEMPLATE2(dereferenceable) + +// indexable doesn't follow the patterns above (it has 4 template arguments), so +// we just write out the compiler hacks explicitly. +#ifdef BOOST_NO_OPERATORS_IN_NAMESPACE +# ifdef BOOST_NO_USING_TEMPLATE + template + struct indexable : ::indexable {}; +# else + using ::indexable; +# endif +#endif + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct is_chained_base< ::boost::indexable > { + typedef ::boost::detail::true_t operator_template_type; +}; +#endif + +#undef BOOST_OPERATOR_TEMPLATE +#undef BOOST_OPERATOR_TEMPLATE2 +#undef BOOST_OPERATOR_TEMPLATE1 +#undef BOOST_IMPORT_TEMPLATE1 +#undef BOOST_IMPORT_TEMPLATE2 + +// The following 'operators' classes can only be used portably if the derived class +// declares ALL of the required member operators. +template +struct operators2 + : less_than_comparable2 > > > > > > > > > {}; + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct operators : operators2 {}; + +template struct operators +#else +template struct operators +#endif + : less_than_comparable > > > > > > > > > > > {}; + +// Iterator helper classes (contributed by Jeremy Siek) -------------------// +template +struct forward_iterator_helper + : equality_comparable > > > {}; + +template +struct bidirectional_iterator_helper + : equality_comparable > > > > {}; + +template +struct random_access_iterator_helper + : equality_comparable > > > > > > > > +{ +#ifndef __BORLANDC__ + friend D requires_difference_operator(const T& x, const T& y) { + return x - y; + } +#endif +}; // random_access_iterator_helper + +} // namespace boost + +#if defined(__sgi) && !defined(__GNUC__) +#pragma reset woff 1234 +#endif + +#endif // BOOST_OPERATORS_HPP diff --git a/include/boost/utility.hpp b/include/boost/utility.hpp new file mode 100644 index 0000000..44dd5d8 --- /dev/null +++ b/include/boost/utility.hpp @@ -0,0 +1,69 @@ +// boost utility.hpp header file -------------------------------------------// + +// (C) Copyright boost.org 1999. 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. + +// See http://www.boost.org for most recent version including documentation. + +// Classes appear in alphabetical order + +// Revision History +// 26 Jan 00 protected noncopyable destructor added (Miki Jovanovic) +// 10 Dec 99 next() and prior() templates added (Dave Abrahams) +// 30 Aug 99 moved cast templates to cast.hpp (Beman Dawes) +// 3 Aug 99 cast templates added +// 20 Jul 99 name changed to utility.hpp +// 9 Jun 99 protected noncopyable default ctor +// 2 Jun 99 Initial Version. Class noncopyable only contents (Dave Abrahams) + +#ifndef BOOST_UTILITY_HPP +#define BOOST_UTILITY_HPP + +#include +#include // for size_t + +namespace boost +{ + +// next() and prior() template functions -----------------------------------// + + // Helper functions for classes like bidirectional iterators not supporting + // operator+ and operator-. + // + // Usage: + // const std::list::iterator p = get_some_iterator(); + // const std::list::iterator prev = boost::prior(p); + + // Contributed by Dave Abrahams + + template + T next(T x) { return ++x; } + + template + T prior(T x) { return --x; } + + +// class noncopyable -------------------------------------------------------// + + // Private copy constructor and copy assignment ensure classes derived from + // class noncopyable cannot be copied. + + // Contributed by Dave Abrahams + + class noncopyable + { + protected: + noncopyable(){} + ~noncopyable(){} + private: // emphasize the following members are private + noncopyable( const noncopyable& ); + const noncopyable& operator=( const noncopyable& ); + }; // noncopyable + +} // namespace boost + +#endif // BOOST_UTILITY_HPP + diff --git a/iterators_test.cpp b/iterators_test.cpp new file mode 100644 index 0000000..e264aff --- /dev/null +++ b/iterators_test.cpp @@ -0,0 +1,169 @@ +// Demonstrate and test boost/operators.hpp on std::iterators --------------// + +// (C) Copyright Jeremy Siek 1999. 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. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 12 Dec 99 Initial version with iterator operators (Jeremy Siek) + +#include +#include +using namespace std; + +#include +using namespace boost; + + +template +struct test_iter + : public boost::random_access_iterator_helper< + test_iter, T, std::ptrdiff_t, P, R> +{ + typedef test_iter self; + typedef R Reference; + typedef std::ptrdiff_t Distance; + +public: + test_iter(T* i) : _i(i) { } + test_iter(const self& x) : _i(x._i) { } + self& operator=(const self& x) { _i = x._i; return *this; } + Reference operator*() const { return *_i; } + self& operator++() { ++_i; return *this; } + self& operator--() { --_i; return *this; } + self& operator+=(Distance n) { _i += n; return *this; } + self& operator-=(Distance n) { _i -= n; return *this; } + bool operator==(const self& x) const { return _i == x._i; } + bool operator<(const self& x) const { return _i < x._i; } + friend Distance operator-(const self& x, const self& y) { + return x._i - y._i; + } +protected: + T* _i; +}; + + +int +main() +{ + string array[] = { "apple", "orange", "pear", "peach", "grape", "plum" }; + { + test_iter i = array, + ie = array + sizeof(array)/sizeof(string); + + // Tests for all of the operators added by random_access_iterator_helper + + // test i++ + while (i != ie) + cout << *i++ << " "; + cout << endl; + i = array; + + // test i-- + while (ie != i) { + ie--; + cout << *ie << " "; + } + cout << endl; + ie = array + sizeof(array)/sizeof(string); + + // test i->m + while (i != ie) { + cout << i->size() << " "; + ++i; + } + cout << endl; + i = array; + + // test i + n + while (i < ie) { + cout << *i << " "; + i = i + 2; + } + cout << endl; + i = array; + + // test n + i + while (i < ie) { + cout << *i << " "; + i = ptrdiff_t(2) + i; + } + cout << endl; + i = array; + + // test i - n + while (ie > i) { + ie = ie - 2; + cout << *ie << " "; + } + cout << endl; + ie = array + sizeof(array)/sizeof(string); + + // test i[n] + for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j) + cout << i[j] << " "; + cout << endl; + } + { + test_iter i = array, + ie = array + sizeof(array)/sizeof(string); + + // Tests for all of the operators added by random_access_iterator_helper + + // test i++ + while (i != ie) + cout << *i++ << " "; + cout << endl; + i = array; + + // test i-- + while (ie != i) { + ie--; + cout << *ie << " "; + } + cout << endl; + ie = array + sizeof(array)/sizeof(string); + + // test i->m + while (i != ie) { + cout << i->size() << " "; + ++i; + } + cout << endl; + i = array; + + // test i + n + while (i < ie) { + cout << *i << " "; + i = i + 2; + } + cout << endl; + i = array; + + // test n + i + while (i < ie) { + cout << *i << " "; + i = ptrdiff_t(2) + i; + } + cout << endl; + i = array; + + // test i - n + while (ie > i) { + ie = ie - 2; + cout << *ie << " "; + } + cout << endl; + ie = array + sizeof(array)/sizeof(string); + + // test i[n] + for (std::size_t j = 0; j < sizeof(array)/sizeof(string); ++j) + cout << i[j] << " "; + cout << endl; + } + return 0; +} diff --git a/noncopyable_test.cpp b/noncopyable_test.cpp new file mode 100644 index 0000000..e5103fb --- /dev/null +++ b/noncopyable_test.cpp @@ -0,0 +1,38 @@ +// boost class noncopyable test program ------------------------------------// + +// (C) Copyright boost.org 1999. 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. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 9 Jun 99 Add unnamed namespace +// 2 Jun 99 Initial Version + +#include +#include + +// This program demonstrates compiler errors resulting from trying to copy +// construct or copy assign a class object derived from class noncopyable. + +namespace +{ + class DontTreadOnMe : boost::noncopyable + { + public: + DontTreadOnMe() { std::cout << "defanged!" << std::endl; } + }; // DontTreadOnMe + +} // unnamed namespace + +int main() +{ + DontTreadOnMe object1; + DontTreadOnMe object2(object1); + object1 = object2; + return 0; +} // main + \ No newline at end of file diff --git a/operators_test.cpp b/operators_test.cpp new file mode 100644 index 0000000..a194521 --- /dev/null +++ b/operators_test.cpp @@ -0,0 +1,481 @@ +// Demonstrate and test boost/operators.hpp -------------------------------// + +// (C) Copyright Beman Dawes 1999. 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. + +// See http://www.boost.org for most recent version including documentation. + +// Revision History +// 04 Jun 00 Added regression test for a bug I found (David Abrahams) +// 17 Jun 00 Fix for broken compilers (Aleksey Gurtovoy) +// ?? ??? 00 Major update to randomly test all one- and two- argument forms by +// wrapping integral types and comparing the results of operations to +// the results for the raw types (David Abrahams) +// 12 Dec 99 Minor update, output confirmation message. +// 15 Nov 99 Initial version + +#include +#include +#include +#include + + +namespace +{ + // avoiding a template version of true_value so as to not confuse VC++ + int true_value(int x) { return x; } + long true_value(long x) { return x; } + signed char true_value(signed char x) { return x; } + unsigned int true_value(unsigned int x) { return x; } + unsigned long true_value(unsigned long x) { return x; } + unsigned char true_value(unsigned char x) { return x; } + + // The use of operators<> here tended to obscure interactions with certain + // compiler bugs + template + class Wrapped1 : boost::operators > + { + public: + explicit Wrapped1( T v = T() ) : _value(v) {} + T value() const { return _value; } + + bool operator<(const Wrapped1& x) const { return _value < x._value; } + bool operator==(const Wrapped1& x) const { return _value == x._value; } + + Wrapped1& operator+=(const Wrapped1& x) + { _value += x._value; return *this; } + Wrapped1& operator-=(const Wrapped1& x) + { _value -= x._value; return *this; } + Wrapped1& operator*=(const Wrapped1& x) + { _value *= x._value; return *this; } + Wrapped1& operator/=(const Wrapped1& x) + { _value /= x._value; return *this; } + Wrapped1& operator%=(const Wrapped1& x) + { _value %= x._value; return *this; } + Wrapped1& operator|=(const Wrapped1& x) + { _value |= x._value; return *this; } + Wrapped1& operator&=(const Wrapped1& x) + { _value &= x._value; return *this; } + Wrapped1& operator^=(const Wrapped1& x) + { _value ^= x._value; return *this; } + Wrapped1& operator++() { ++_value; return *this; } + Wrapped1& operator--() { --_value; return *this; } + + private: + T _value; + }; + template + T true_value(Wrapped1 x) { return x.value(); } + + template + class Wrapped2 : + boost::operators >, + boost::operators2, U> + { + public: + explicit Wrapped2( T v = T() ) : _value(v) {} + T value() const { return _value; } + + bool operator<(const Wrapped2& x) const { return _value < x._value; } + bool operator==(const Wrapped2& x) const { return _value == x._value; } + + Wrapped2& operator+=(const Wrapped2& x) + { _value += x._value; return *this; } + Wrapped2& operator-=(const Wrapped2& x) + { _value -= x._value; return *this; } + Wrapped2& operator*=(const Wrapped2& x) + { _value *= x._value; return *this; } + Wrapped2& operator/=(const Wrapped2& x) + { _value /= x._value; return *this; } + Wrapped2& operator%=(const Wrapped2& x) + { _value %= x._value; return *this; } + Wrapped2& operator|=(const Wrapped2& x) + { _value |= x._value; return *this; } + Wrapped2& operator&=(const Wrapped2& x) + { _value &= x._value; return *this; } + Wrapped2& operator^=(const Wrapped2& x) + { _value ^= x._value; return *this; } + Wrapped2& operator++() { ++_value; return *this; } + Wrapped2& operator--() { --_value; return *this; } + + bool operator<(U u) const { return _value < u; } + bool operator>(U u) const { return _value > u; } + bool operator==(U u) const { return _value == u; } + Wrapped2& operator+=(U u) { _value += u; return *this; } + Wrapped2& operator-=(U u) { _value -= u; return *this; } + Wrapped2& operator*=(U u) { _value *= u; return *this; } + Wrapped2& operator/=(U u) { _value /= u; return *this; } + Wrapped2& operator%=(U u) { _value %= u; return *this; } + Wrapped2& operator|=(U u) { _value |= u; return *this; } + Wrapped2& operator&=(U u) { _value &= u; return *this; } + Wrapped2& operator^=(U u) { _value ^= u; return *this; } + + private: + T _value; + }; + template + T true_value(Wrapped2 x) { return x.value(); } + + // MyInt uses only the single template-argument form of all_operators<> + typedef Wrapped1 MyInt; + + typedef Wrapped2 MyLong; + + template + void sanity_check(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert(true_value(y1) == true_value(y2)); + assert(true_value(x1) == true_value(x2)); + } + + template + void test_less_than_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 < y1) == (x2 < y2)); + assert((x1 <= y1) == (x2 <= y2)); + assert((x1 >= y1) == (x2 >= y2)); + assert((x1 > y1) == (x2 > y2)); + } + + template + void test_less_than_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_less_than_comparable_aux(x1, y1, x2, y2); + test_less_than_comparable_aux(y1, x1, y2, x2); + } + + template + void test_equality_comparable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 == y1) == (x2 == y2)); + assert((x1 != y1) == (x2 != y2)); + } + + template + void test_equality_comparable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_equality_comparable_aux(x1, y1, x2, y2); + test_equality_comparable_aux(y1, x1, y2, x2); + } + + template + void test_multipliable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 * y1).value() == (x2 * y2)); + } + + template + void test_multipliable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_multipliable_aux(x1, y1, x2, y2); + test_multipliable_aux(y1, x1, y2, x2); + } + + template + void test_addable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 + y1).value() == (x2 + y2)); + } + + template + void test_addable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_addable_aux(x1, y1, x2, y2); + test_addable_aux(y1, x1, y2, x2); + } + + template + void test_subtractable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + assert((x1 - y1).value() == x2 - y2); + } + + template + void test_dividable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + if (y2 != 0) + assert((x1 / y1).value() == x2 / y2); + } + + template + void test_modable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + if (y2 != 0) + assert((x1 / y1).value() == x2 / y2); + } + + template + void test_xorable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 ^ y1).value() == (x2 ^ y2)); + } + + template + void test_xorable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_xorable_aux(x1, y1, x2, y2); + test_xorable_aux(y1, x1, y2, x2); + } + + template + void test_andable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 & y1).value() == (x2 & y2)); + } + + template + void test_andable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_andable_aux(x1, y1, x2, y2); + test_andable_aux(y1, x1, y2, x2); + } + + template + void test_orable_aux(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + assert((x1 | y1).value() == (x2 | y2)); + } + + template + void test_orable(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + sanity_check(x1, y1, x2, y2); + test_orable_aux(x1, y1, x2, y2); + test_orable_aux(y1, x1, y2, x2); + } + + template + void test_incrementable(X1 x1, X2 x2) + { + sanity_check(x1, x1, x2, x2); + assert(x1++.value() == x2++); + assert(x1.value() == x2); + } + + template + void test_decrementable(X1 x1, X2 x2) + { + sanity_check(x1, x1, x2, x2); + assert(x1--.value() == x2--); + assert(x1.value() == x2); + } + + template + void test_all(X1 x1, Y1 y1, X2 x2, Y2 y2) + { + test_less_than_comparable(x1, y1, x2, y2); + test_equality_comparable(x1, y1, x2, y2); + test_multipliable(x1, y1, x2, y2); + test_addable(x1, y1, x2, y2); + test_subtractable(x1, y1, x2, y2); + test_dividable(x1, y1, x2, y2); + test_modable(x1, y1, x2, y2); + test_xorable(x1, y1, x2, y2); + test_andable(x1, y1, x2, y2); + test_orable(x1, y1, x2, y2); + test_incrementable(x1, x2); + test_decrementable(x1, x2); + } + + template + struct tester + { + void operator()(boost::min_rand& randomizer) const + { + Big b1 = Big(randomizer()); + Big b2 = Big(randomizer()); + Small s = Small(randomizer()); + + test_all(Wrapped1(b1), Wrapped1(b2), b1, b2); + test_all(Wrapped2(b1), s, b1, s); + } + }; + + // added as a regression test. We had a bug which this uncovered. + struct Point + : boost::addable > + { + Point( int h, int v ) : h(h), v(v) {} + Point() :h(0), v(0) {} + const Point& operator+=( const Point& rhs ) { h += rhs.h; v += rhs.v; return *this; } + const Point& operator-=( const Point& rhs ) { h -= rhs.h; v -= rhs.v; return *this; } + + int h; + int v; + }; +} // unnamed namespace + + +// workaround for MSVC bug; for some reasons the compiler doesn't instantiate +// inherited operator templates at the moment it must, so the following +// explicit instantiations force it to do that. + +#if defined(BOOST_MSVC) && (_MSC_VER <= 1200) +template Wrapped1; +template Wrapped1; +template Wrapped1; +template Wrapped1; + +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +template Wrapped2; +#endif + +#ifdef NDEBUG +#error This program is pointless when NDEBUG disables assert()! +#endif + +int main() +{ + // Regression test. + Point x; + x = x + Point(3, 4); + x = x - Point(3, 4); + + for (int n = 0; n < 10000; ++n) + { + boost::min_rand r; + tester()(r); + tester()(r); + tester()(r); + tester()(r); + tester()(r); + + tester()(r); + tester()(r); + tester()(r); + tester()(r); + tester()(r); + } + + MyInt i1(1); + MyInt i2(2); + MyInt i; + + assert( i1.value() == 1 ); + assert( i2.value() == 2 ); + assert( i.value() == 0 ); + + i = i2; + assert( i.value() == 2 ); + assert( i2 == i ); + assert( i1 != i2 ); + assert( i1 < i2 ); + assert( i1 <= i2 ); + assert( i <= i2 ); + assert( i2 > i1 ); + assert( i2 >= i1 ); + assert( i2 >= i ); + + i = i1 + i2; assert( i.value() == 3 ); + i = i + i2; assert( i.value() == 5 ); + i = i - i1; assert( i.value() == 4 ); + i = i * i2; assert( i.value() == 8 ); + i = i / i2; assert( i.value() == 4 ); + i = i % (i - i1); assert( i.value() == 1 ); + i = i2 + i2; assert( i.value() == 4 ); + i = i1 | i2 | i; assert( i.value() == 7 ); + i = i & i2; assert( i.value() == 2 ); + i = i + i1; assert( i.value() == 3 ); + i = i ^ i1; assert( i.value() == 2 ); + i = (i+i1)*(i2|i1); assert( i.value() == 9 ); + + MyLong j1(1); + MyLong j2(2); + MyLong j; + + assert( j1.value() == 1 ); + assert( j2.value() == 2 ); + assert( j.value() == 0 ); + + j = j2; + assert( j.value() == 2 ); + + assert( j2 == j ); + assert( 2 == j ); + assert( j2 == 2 ); + assert( j == j2 ); + assert( j1 != j2 ); + assert( j1 != 2 ); + assert( 1 != j2 ); + assert( j1 < j2 ); + assert( 1 < j2 ); + assert( j1 < 2 ); + assert( j1 <= j2 ); + assert( 1 <= j2 ); + assert( j1 <= j ); + assert( j <= j2 ); + assert( 2 <= j2 ); + assert( j <= 2 ); + assert( j2 > j1 ); + assert( 2 > j1 ); + assert( j2 > 1 ); + assert( j2 >= j1 ); + assert( 2 >= j1 ); + assert( j2 >= 1 ); + assert( j2 >= j ); + assert( 2 >= j ); + assert( j2 >= 2 ); + + assert( (j1 + 2) == 3 ); + assert( (1 + j2) == 3 ); + j = j1 + j2; assert( j.value() == 3 ); + + assert( (j + 2) == 5 ); + assert( (3 + j2) == 5 ); + j = j + j2; assert( j.value() == 5 ); + + assert( (j - 1) == 4 ); + j = j - j1; assert( j.value() == 4 ); + + assert( (j * 2) == 8 ); + assert( (4 * j2) == 8 ); + j = j * j2; assert( j.value() == 8 ); + + assert( (j / 2) == 4 ); + j = j / j2; assert( j.value() == 4 ); + + assert( (j % 3) == 1 ); + j = j % (j - j1); assert( j.value() == 1 ); + + j = j2 + j2; assert( j.value() == 4 ); + + assert( (1 | j2 | j) == 7 ); + assert( (j1 | 2 | j) == 7 ); + assert( (j1 | j2 | 4) == 7 ); + j = j1 | j2 | j; assert( j.value() == 7 ); + + assert( (7 & j2) == 2 ); + assert( (j & 2) == 2 ); + j = j & j2; assert( j.value() == 2 ); + + j = j | j1; assert( j.value() == 3 ); + + assert( (3 ^ j1) == 2 ); + assert( (j ^ 1) == 2 ); + j = j ^ j1; assert( j.value() == 2 ); + + j = (j+j1)*(j2|j1); assert( j.value() == 9 ); + + std::cout << "0 errors detected\n"; + return 0; +} diff --git a/type_traits_test.cpp b/type_traits_test.cpp new file mode 100644 index 0000000..ffea91d --- /dev/null +++ b/type_traits_test.cpp @@ -0,0 +1,623 @@ +// (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. + +#include +#include + +#include +#include +#include + +using namespace boost; + +#ifdef __BORLANDC__ +#pragma option -w-ccc -w-rch -w-eff -w-aus +#endif + +// +// define tests here +unsigned failures = 0; + +#define value_test(v, x) if(v == x) /*std::cout << "checking value of " << #x << "...OK" << std::endl*/;\ + else{++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} + +#define type_test(v, x) if(is_same::value) /*std::cout << "checking type of " << #x << "...OK" << std::endl*/;\ + else{++failures; std::cout << "checking type of " << #x << "...failed (type was: " << typeid(is_same).name() << ")" << std::endl;} + +template +struct call_traits_test +{ + static void assert_construct(call_traits::param_type val); +}; + +template +void call_traits_test::assert_construct(call_traits::param_type val) +{ + // + // this is to check that the call_traits assertions are valid: + T t(val); + call_traits::value_type v(t); + call_traits::reference r(t); + call_traits::const_reference cr(t); + call_traits::param_type p(t); + call_traits::value_type v2(v); + call_traits::value_type v3(r); + call_traits::value_type v4(p); + call_traits::reference r2(v); + call_traits::reference r3(r); + call_traits::const_reference cr2(v); + call_traits::const_reference cr3(r); + call_traits::const_reference cr4(cr); + call_traits::const_reference cr5(p); + call_traits::param_type p2(v); + call_traits::param_type p3(r); + call_traits::param_type p4(p); +} +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct call_traits_test +{ + static void assert_construct(call_traits::param_type val); +}; + +template +void call_traits_test::assert_construct(call_traits::param_type val) +{ + // + // this is to check that the call_traits assertions are valid: + T t; + call_traits::value_type v(t); + call_traits::reference r(t); + call_traits::const_reference cr(t); + call_traits::param_type p(t); + call_traits::value_type v2(v); + call_traits::value_type v3(r); + call_traits::value_type v4(p); + call_traits::reference r2(v); + call_traits::reference r3(r); + call_traits::const_reference cr2(v); + call_traits::const_reference cr3(r); + call_traits::const_reference cr4(cr); + call_traits::const_reference cr5(p); + call_traits::param_type p2(v); + call_traits::param_type p3(r); + call_traits::param_type p4(p); +} +#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +// 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 }; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { +template <> struct is_enum +{ static const bool value = true; }; +} +#endif +struct UDT +{ + UDT(); + ~UDT(); + UDT(const UDT&); + UDT& operator=(const UDT&); + int i; + + void f1(); + int f2(); + int f3(int); + int f4(int, float); +}; + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +struct POD_UDT { int x; }; +namespace boost { +template <> struct is_POD +{ static const bool value = true; }; +} +#endif +struct empty_UDT +{ + ~empty_UDT(){}; +}; +namespace boost { +//template <> struct is_empty +//{ static const bool value = true; }; +// this type is not POD, so we have to specialize the has_* individually +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +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; }; +} +#endif + +struct empty_POD_UDT{}; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { +template <> struct is_empty +{ static const bool value = true; }; +template <> struct is_POD +{ static const bool value = true; }; +} +#endif +union union_UDT +{ + int x; + double y; + ~union_UDT(); +}; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { +template <> struct is_union +{ static const bool value = true; }; +} +#endif +union POD_union_UDT +{ + int x; + double y; +}; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { +template <> struct is_union +{ static const bool value = true; }; +template <> struct is_POD +{ static const bool value = true; }; +} +#endif +union empty_union_UDT +{ + ~empty_union_UDT(); +}; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { +template <> struct is_union +{ static const bool value = true; }; +template <> struct is_empty +{ 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; }; +} +#endif +union empty_POD_union_UDT{}; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { +template <> struct is_union +{ static const bool value = true; }; +template <> struct is_empty +{ static const bool value = true; }; +template <> struct is_POD +{ static const bool value = true; }; +#endif +} +// 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() +{ + std::cout << "Checking type operations..." << std::endl << std::endl; + + 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_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) + + type_test(const int, call_traits::param_type) + type_test(const char, call_traits::param_type) +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + type_test(char&, call_traits::param_type) + type_test(const char&, call_traits::param_type) +#endif + std::cout << std::endl << "Checking type properties..." << std::endl << std::endl; + + 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 + 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(true, is_array::value) + value_test(true, 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_pointer::value) + value_test(false, 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) + 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(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) + value_test(false, is_empty::value) + value_test(false, is_empty::value) + value_test(false, is_empty::value) + value_test(false, is_empty::value) + 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) + + compressed_pair cp1; + compressed_pair cp1b; + swap(cp1, cp1b); + compressed_pair cp2; + compressed_pair cp3; + compressed_pair cp4; + compressed_pair cp5; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + int i; + compressed_pair cp6(i,i); + compressed_pair cp7; + cp7.first(); + double* pd = cp7.second(); +#endif + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + + std::cout << std::endl << "Tests completed (" << failures << " failures)... press any key to exit"; + std::cin.get(); + return 0; +} + +// +// instanciate some compressed pairs: +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +// +// now some for which only a few specific members can be instantiated, +// first references: +template double& compressed_pair::first(); +template int& compressed_pair::second(); +template compressed_pair::compressed_pair(int&); +template compressed_pair::compressed_pair(call_traits::param_type,int&); +// +// and then arrays: +#ifndef __BORLANDC__ +template call_traits::reference compressed_pair::second(); +#endif +template call_traits::reference compressed_pair::first(); +template compressed_pair::compressed_pair(const double&); +template compressed_pair::compressed_pair(); +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +// +// now check call_traits assertions by instantiating call_traits_test: +template struct call_traits_test; +template struct call_traits_test; +template struct call_traits_test; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template struct call_traits_test; +template struct call_traits_test; +// this doesn't work (yet) (JM): +template struct call_traits_test; +#endif + + From a005f03cc2d40c8397daba55d44d85c146c3b22b Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 24 Jul 2000 17:59:52 +0000 Subject: [PATCH 02/12] Fixes for various compilers from John Maddock [SVN r7629] --- algo_opt_examples.cpp | 91 +++--- call_traits_test.cpp | 254 +++++++++++++--- include/boost/detail/call_traits.hpp | 42 ++- include/boost/detail/ob_compressed_pair.hpp | 12 +- type_traits_test.cpp | 303 +++++++------------- 5 files changed, 418 insertions(+), 284 deletions(-) diff --git a/algo_opt_examples.cpp b/algo_opt_examples.cpp index 6b795e7..759a0ed 100644 --- a/algo_opt_examples.cpp +++ b/algo_opt_examples.cpp @@ -24,6 +24,13 @@ * */ +/* 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 @@ -39,6 +46,10 @@ 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{ // @@ -221,6 +232,10 @@ struct swapper } }; +#ifdef __GNUC__ +using std::swap; +#endif + template <> struct swapper { @@ -295,6 +310,44 @@ int main() 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); @@ -347,43 +400,6 @@ int main() result = t.elapsed(); cout << "standard \"unoptimised\" copy: " << 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; // // testing iter_swap @@ -404,3 +420,4 @@ int main() + diff --git a/call_traits_test.cpp b/call_traits_test.cpp index c615013..c89169f 100644 --- a/call_traits_test.cpp +++ b/call_traits_test.cpp @@ -6,6 +6,12 @@ #include #include +#ifdef __BORLANDC__ +// turn off some warnings, the way we do the tests will generate a *lot* of these +// this is a result of the tests not call_traits itself.... +#pragma option -w-8004 -w-ccc -w-rch -w-eff -w-aus +#endif + // // struct contained models a type that contains a type (for example std::pair) // arrays are contained by value, and have to be treated as a special case: @@ -28,7 +34,7 @@ struct contained contained() {} contained(param_type p) : v_(p){} // return byval: - result_type value() { return v_; } + result_type value()const { return v_; } // return by_ref: reference get() { return v_; } const_reference const_get()const { return v_; } @@ -37,6 +43,7 @@ struct contained }; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct contained { @@ -53,30 +60,36 @@ struct contained std::copy(p, p+N, v_); } // return byval: - result_type value() { return v_; } + result_type value()const { return v_; } // return by_ref: reference get() { return v_; } const_reference const_get()const { return v_; } void call(param_type p){} }; +#endif template contained::value_type> wrap(const T& t) { - return contained::value_type>(t); + typedef typename boost::call_traits::value_type ct; + return contained(t); } +namespace test{ + template std::pair< - typename boost::call_traits::value_type, - typename boost::call_traits::value_type> + typename boost::call_traits::value_type, + typename boost::call_traits::value_type> make_pair(const T1& t1, const T2& t2) { return std::pair< - typename boost::call_traits::value_type, + typename boost::call_traits::value_type, typename boost::call_traits::value_type>(t1, t2); } +} // namespace test + using namespace std; // @@ -108,51 +121,40 @@ void checker::operator()(param_type p) cout << endl; } +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct checker { typedef typename boost::call_traits::param_type param_type; - void operator()(param_type); + void operator()(param_type t) + { + contained c(t); + cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl; + unsigned int i = 0; + for(i = 0; i < N; ++i) + assert(t[i] == c.value()[i]); + for(i = 0; i < N; ++i) + assert(t[i] == c.get()[i]); + for(i = 0; i < N; ++i) + assert(t[i] == c.const_get()[i]); + + cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained::value).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained::get).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained::const_get).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained::call).name() << endl; + cout << endl; + } }; - -template -void checker::operator()(param_type t) -{ - contained c(t); - cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl; - unsigned int i = 0; - for(i = 0; i < N; ++i) - assert(t[i] == c.value()[i]); - for(i = 0; i < N; ++i) - assert(t[i] == c.get()[i]); - for(i = 0; i < N; ++i) - assert(t[i] == c.const_get()[i]); - - cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; - cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained::value).name() << endl; - cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained::get).name() << endl; - cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained::const_get).name() << endl; - cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained::call).name() << endl; - cout << endl; -} +#endif // // check_wrap: -// verifies behaviour of "wrap": -// -template -void check_wrap(T c, U u, const V& v) +template +void check_wrap(const contained& w, const U& u) { - cout << "checking contained<" << typeid(T::value_type).name() << ">..." << endl; - assert(c.get() == u); - cout << "typeof deduced argument was: " << typeid(V).name() << endl; - cout << "typeof deduced parameter after adjustment was: " << typeid(v).name() << endl; - cout << "typeof contained<" << typeid(T::value_type).name() << ">::v_ is: " << typeid(&T::v_).name() << endl; - cout << "typeof contained<" << typeid(T::value_type).name() << ">::value is: " << typeid(&T::value).name() << endl; - cout << "typeof contained<" << typeid(T::value_type).name() << ">::get is: " << typeid(&T::get).name() << endl; - cout << "typeof contained<" << typeid(T::value_type).name() << ">::const_get is: " << typeid(&T::const_get).name() << endl; - cout << "typeof contained<" << typeid(T::value_type).name() << ">::call is: " << typeid(&T::call).name() << endl; - cout << endl; + cout << "checking contained<" << typeid(T).name() << ">..." << endl; + assert(w.value() == u); } // @@ -176,6 +178,29 @@ struct UDT bool operator == (const UDT& v){ return v.i_ == i_; } }; +// +// define tests here +unsigned failures = 0; +unsigned test_count = 0; + +#define value_test(v, x) ++test_count;\ + if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#define type_test(v, x) ++test_count;\ + if(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 int main() { @@ -188,6 +213,7 @@ int main() int* pi = &i; checker c3; c3(pi); +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION checker c4; c4(i); checker c5; @@ -196,13 +222,147 @@ int main() int a[2] = {1,2}; checker c6; c6(a); +#endif - check_wrap(wrap(2), 2, 2); + check_wrap(wrap(2), 2); const char ca[4] = "abc"; // compiler can't deduce this for some reason: - //check_wrap(wrap(ca), ca, ca); - check_wrap(wrap(a), a, a); - check_make_pair(::make_pair(a, a), a, a); + //check_wrap(wrap(ca), ca); +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + check_wrap(wrap(a), a); + check_make_pair(test::make_pair(a, a), a, a); +#endif - return 0; + // 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; + typedef const r_type cr_type; + + type_test(UDT, boost::call_traits::value_type) + type_test(UDT&, boost::call_traits::reference) + type_test(const UDT&, boost::call_traits::const_reference) + type_test(const UDT&, boost::call_traits::param_type) + type_test(int, boost::call_traits::value_type) + type_test(int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(const int, boost::call_traits::param_type) + type_test(int*, boost::call_traits::value_type) + type_test(int*&, boost::call_traits::reference) + type_test(int*const&, boost::call_traits::const_reference) + type_test(int*const, boost::call_traits::param_type) +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + type_test(int&, boost::call_traits::value_type) + type_test(int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(int&, boost::call_traits::param_type) +#if !(defined(__GNUC__) && (__GNUC__ < 3)) + type_test(int&, boost::call_traits::value_type) + type_test(int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(int&, boost::call_traits::param_type) +#else + std::cout << "GNU C++ cannot instantiate call_traits, skipping four tests (4 errors)" << std::endl; + failures += 4; + test_count += 4; +#endif + type_test(const int&, boost::call_traits::value_type) + type_test(const int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(const int&, boost::call_traits::param_type) + type_test(const int*, boost::call_traits::value_type) + type_test(int(&)[3], boost::call_traits::reference) + type_test(const int(&)[3], boost::call_traits::const_reference) + type_test(const int*const, boost::call_traits::param_type) + type_test(const int*, boost::call_traits::value_type) + type_test(const int(&)[3], boost::call_traits::reference) + type_test(const int(&)[3], boost::call_traits::const_reference) + type_test(const int*const, boost::call_traits::param_type) +#else + std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl; + failures += 20; + test_count += 20; +#endif + + std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; + std::cin.get(); + return failures; } + +// +// define call_traits tests to check that the assertions in the docs do actually work +// this is an instantiate only set of tests: +// +template +struct call_traits_test +{ + static void assert_construct(boost::call_traits::param_type val); +}; + +template +void call_traits_test::assert_construct(boost::call_traits::param_type val) +{ + // + // this is to check that the call_traits assertions are valid: + T t(val); + boost::call_traits::value_type v(t); + boost::call_traits::reference r(t); + boost::call_traits::const_reference cr(t); + boost::call_traits::param_type p(t); + boost::call_traits::value_type v2(v); + boost::call_traits::value_type v3(r); + boost::call_traits::value_type v4(p); + boost::call_traits::reference r2(v); + boost::call_traits::reference r3(r); + boost::call_traits::const_reference cr2(v); + boost::call_traits::const_reference cr3(r); + boost::call_traits::const_reference cr4(cr); + boost::call_traits::const_reference cr5(p); + boost::call_traits::param_type p2(v); + boost::call_traits::param_type p3(r); + boost::call_traits::param_type p4(p); +} +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct call_traits_test +{ + static void assert_construct(boost::call_traits::param_type val); +}; + +template +void call_traits_test::assert_construct(boost::call_traits::param_type val) +{ + // + // this is to check that the call_traits assertions are valid: + T t; + boost::call_traits::value_type v(t); + boost::call_traits::value_type v5(val); + boost::call_traits::reference r = t; + boost::call_traits::const_reference cr = t; + boost::call_traits::reference r2 = r; + #ifndef __BORLANDC__ + // C++ Builder buglet: + boost::call_traits::const_reference cr2 = r; + #endif + boost::call_traits::param_type p(t); + boost::call_traits::value_type v2(v); + boost::call_traits::const_reference cr3 = cr; + boost::call_traits::value_type v3(r); + boost::call_traits::value_type v4(p); + boost::call_traits::param_type p2(v); + boost::call_traits::param_type p3(r); + boost::call_traits::param_type p4(p); +} +#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +// +// now check call_traits assertions by instantiating call_traits_test: +template struct call_traits_test; +template struct call_traits_test; +template struct call_traits_test; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template struct call_traits_test; +template struct call_traits_test; +template struct call_traits_test; +#endif + + diff --git a/include/boost/detail/call_traits.hpp b/include/boost/detail/call_traits.hpp index 07ed4ec..93dc7b1 100644 --- a/include/boost/detail/call_traits.hpp +++ b/include/boost/detail/call_traits.hpp @@ -6,6 +6,13 @@ // See http://www.boost.org for most recent version including documentation. +/* Release notes: + 23rd July 2000: + Fixed array specialization. (JM) + Added Borland specific fixes for reference types + (issue raised by Steve Cleary). +*/ + #ifndef BOOST_DETAIL_CALL_TRAITS_HPP #define BOOST_DETAIL_CALL_TRAITS_HPP @@ -66,6 +73,37 @@ struct call_traits typedef T& param_type; // hh removed const }; +#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x550) +// these are illegal specialisations; cv-qualifies applied to +// references have no effect according to [8.3.2p1], +// C++ Builder requires them though as it treats cv-qualified +// references as distinct types... +template +struct call_traits +{ + typedef T& value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T& param_type; // hh removed const +}; +template +struct call_traits +{ + typedef T& value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T& param_type; // hh removed const +}; +template +struct call_traits +{ + typedef T& value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T& param_type; // hh removed const +}; +#endif + template struct call_traits { @@ -76,7 +114,7 @@ public: typedef const T* value_type; typedef array_type& reference; typedef const array_type& const_reference; - typedef const T* param_type; + typedef const T* const param_type; }; template @@ -89,7 +127,7 @@ public: typedef const T* value_type; typedef array_type& reference; typedef const array_type& const_reference; - typedef const T* param_type; + typedef const T* const param_type; }; } diff --git a/include/boost/detail/ob_compressed_pair.hpp b/include/boost/detail/ob_compressed_pair.hpp index f5f5664..ce7e064 100644 --- a/include/boost/detail/ob_compressed_pair.hpp +++ b/include/boost/detail/ob_compressed_pair.hpp @@ -6,7 +6,14 @@ // See http://www.boost.org for most recent version including documentation. // -// this version crippled for use with crippled compilers - John Maddock Jan 2000. +/* Release notes: + 23rd July 2000: + Additional comments added. (JM) + Jan 2000: + Original version: this version crippled for use with crippled compilers + - John Maddock Jan 2000. +*/ + #ifndef BOOST_OB_COMPRESSED_PAIR_HPP #define BOOST_OB_COMPRESSED_PAIR_HPP @@ -41,7 +48,8 @@ public: compressed_pair() : _first(), _second() {} compressed_pair(first_param_type x, second_param_type y) : _first(x), _second(y) {} explicit compressed_pair(first_param_type x) : _first(x), _second() {} - //explicit compressed_pair(second_param_type y) : _first(), _second(y) {} + // can't define this in case T1 == T2: + // explicit compressed_pair(second_param_type y) : _first(), _second(y) {} first_reference first() { return _first; } first_const_reference first() const { return _first; } diff --git a/type_traits_test.cpp b/type_traits_test.cpp index ffea91d..b50892a 100644 --- a/type_traits_test.cpp +++ b/type_traits_test.cpp @@ -4,12 +4,18 @@ // 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. +/* Release notes: + 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 using namespace boost; @@ -20,73 +26,25 @@ using namespace boost; // // define tests here unsigned failures = 0; +unsigned test_count = 0; -#define value_test(v, x) if(v == x) /*std::cout << "checking value of " << #x << "...OK" << std::endl*/;\ - else{++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} - -#define type_test(v, x) if(is_same::value) /*std::cout << "checking type of " << #x << "...OK" << std::endl*/;\ - else{++failures; std::cout << "checking type of " << #x << "...failed (type was: " << typeid(is_same).name() << ")" << std::endl;} - -template -struct call_traits_test -{ - static void assert_construct(call_traits::param_type val); -}; - -template -void call_traits_test::assert_construct(call_traits::param_type val) -{ - // - // this is to check that the call_traits assertions are valid: - T t(val); - call_traits::value_type v(t); - call_traits::reference r(t); - call_traits::const_reference cr(t); - call_traits::param_type p(t); - call_traits::value_type v2(v); - call_traits::value_type v3(r); - call_traits::value_type v4(p); - call_traits::reference r2(v); - call_traits::reference r3(r); - call_traits::const_reference cr2(v); - call_traits::const_reference cr3(r); - call_traits::const_reference cr4(cr); - call_traits::const_reference cr5(p); - call_traits::param_type p2(v); - call_traits::param_type p3(r); - call_traits::param_type p4(p); -} +#define value_test(v, x) ++test_count;\ + if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -template -struct call_traits_test -{ - static void assert_construct(call_traits::param_type val); -}; - -template -void call_traits_test::assert_construct(call_traits::param_type val) -{ - // - // this is to check that the call_traits assertions are valid: - T t; - call_traits::value_type v(t); - call_traits::reference r(t); - call_traits::const_reference cr(t); - call_traits::param_type p(t); - call_traits::value_type v2(v); - call_traits::value_type v3(r); - call_traits::value_type v4(p); - call_traits::reference r2(v); - call_traits::reference r3(r); - call_traits::const_reference cr2(v); - call_traits::const_reference cr3(r); - call_traits::const_reference cr4(cr); - call_traits::const_reference cr5(p); - call_traits::param_type p2(v); - call_traits::param_type p3(r); - call_traits::param_type p4(p); -} -#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#define type_test(v, x) ++test_count;\ + if(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(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 // Since there is no compiler support, we should specialize: // is_enum for all enumerations (is_enum implies is_POD) @@ -96,12 +54,6 @@ void call_traits_test::assert_construct(call_traits::param_type val) // has_* for any UDT that has that trait and is not POD enum enum_UDT{ one, two, three }; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -namespace boost { -template <> struct is_enum -{ static const bool value = true; }; -} -#endif struct UDT { UDT(); @@ -116,74 +68,47 @@ struct UDT int f4(int, float); }; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION struct POD_UDT { int x; }; -namespace boost { -template <> struct is_POD -{ static const bool value = true; }; -} -#endif -struct empty_UDT -{ - ~empty_UDT(){}; -}; -namespace boost { -//template <> struct is_empty -//{ static const bool value = true; }; -// this type is not POD, so we have to specialize the has_* individually -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -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; }; -} -#endif - +struct empty_UDT{ ~empty_UDT(){}; }; struct empty_POD_UDT{}; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -namespace boost { -template <> struct is_empty -{ static const bool value = true; }; -template <> struct is_POD -{ static const bool value = true; }; -} -#endif union union_UDT { int x; double y; ~union_UDT(); }; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -namespace boost { -template <> struct is_union -{ static const bool value = true; }; -} -#endif union POD_union_UDT { int x; double y; }; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -namespace boost { -template <> struct is_union -{ static const bool value = true; }; -template <> struct is_POD -{ static const bool value = true; }; -} -#endif union empty_union_UDT { ~empty_union_UDT(); }; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +union empty_POD_union_UDT{}; +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION namespace boost { -template <> struct is_union +template <> struct is_enum { static const bool value = true; }; -template <> struct is_empty +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 @@ -192,19 +117,48 @@ template <> struct has_trivial_copy { static const bool value = true; }; template <> struct has_trivial_assign { static const bool value = true; }; -} -#endif -union empty_POD_union_UDT{}; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -namespace boost { template <> struct is_union { static const bool value = true; }; -template <> struct is_empty -{ static const bool value = true; }; template <> struct is_POD { static const bool value = true; }; -#endif } +#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 + // 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 @@ -214,11 +168,18 @@ int main() { 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; + typedef const r_type cr_type; + 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) @@ -246,14 +207,15 @@ int main() type_test(int, remove_bounds::type) type_test(int[3], remove_bounds::type) - type_test(const int, call_traits::param_type) - type_test(const char, call_traits::param_type) -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - type_test(char&, call_traits::param_type) - type_test(const char&, call_traits::param_type) -#endif 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(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) @@ -266,7 +228,8 @@ int main() value_test(true, is_void::value) // Steve: fails on BCB4 - value_test(false, is_void::value) + // 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) @@ -432,6 +395,8 @@ int main() 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) @@ -477,8 +442,9 @@ int main() value_test(false, is_empty::value) value_test(false, is_empty::value) value_test(false, is_empty::value) - value_test(false, is_empty::value) value_test(true, is_empty::value) + value_test(true, is_empty::value) + value_test(true, is_empty::value) value_test(false, is_empty::value) value_test(true, has_trivial_constructor::value) @@ -558,66 +524,11 @@ int main() value_test(false, is_POD::value) value_test(true, is_POD::value) - compressed_pair cp1; - compressed_pair cp1b; - swap(cp1, cp1b); - compressed_pair cp2; - compressed_pair cp3; - compressed_pair cp4; - compressed_pair cp5; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - int i; - compressed_pair cp6(i,i); - compressed_pair cp7; - cp7.first(); - double* pd = cp7.second(); -#endif - value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) - value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) - value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) - value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) - - std::cout << std::endl << "Tests completed (" << failures << " failures)... press any key to exit"; + std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; std::cin.get(); - return 0; + return failures; } -// -// instanciate some compressed pairs: -template class boost::compressed_pair; -template class boost::compressed_pair; -template class boost::compressed_pair; -template class boost::compressed_pair; -template class boost::compressed_pair; -template class boost::compressed_pair; - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -// -// now some for which only a few specific members can be instantiated, -// first references: -template double& compressed_pair::first(); -template int& compressed_pair::second(); -template compressed_pair::compressed_pair(int&); -template compressed_pair::compressed_pair(call_traits::param_type,int&); -// -// and then arrays: -#ifndef __BORLANDC__ -template call_traits::reference compressed_pair::second(); -#endif -template call_traits::reference compressed_pair::first(); -template compressed_pair::compressed_pair(const double&); -template compressed_pair::compressed_pair(); -#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -// -// now check call_traits assertions by instantiating call_traits_test: -template struct call_traits_test; -template struct call_traits_test; -template struct call_traits_test; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -template struct call_traits_test; -template struct call_traits_test; -// this doesn't work (yet) (JM): -template struct call_traits_test; -#endif + From 777c931b5dcf51aa763d81c4badc05f134aeff47 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Wed, 26 Jul 2000 17:29:19 +0000 Subject: [PATCH 03/12] Initial version from John Maddock [SVN r7631] --- compressed_pair_test.cpp | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 compressed_pair_test.cpp diff --git a/compressed_pair_test.cpp b/compressed_pair_test.cpp new file mode 100644 index 0000000..ebbaa78 --- /dev/null +++ b/compressed_pair_test.cpp @@ -0,0 +1,140 @@ +// 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. + +#include +#include +#include + +#include + +using namespace boost; + +#ifdef __BORLANDC__ +#pragma option -w-ccc -w-rch -w-eff -w-aus +#endif + +// +// define tests here +unsigned failures = 0; +unsigned test_count = 0; + +#define value_test(v, x) ++test_count;\ + if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +#define type_test(v, x) ++test_count;\ + if(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 + +struct empty_POD_UDT{}; +struct empty_UDT +{ + ~empty_UDT(){}; +}; +namespace boost { +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template <> struct is_empty +{ static const bool value = true; }; +template <> struct is_empty +{ static const bool value = true; }; +template <> struct is_POD +{ static const bool value = true; }; +#else +template <> struct is_empty +{ enum{ value = true }; }; +template <> struct is_empty +{ enum{ value = true }; }; +template <> struct is_POD +{ enum{ value = true }; }; +#endif +} + + +int main() +{ + compressed_pair cp1(1, 1.3); + assert(cp1.first() == 1); + assert(cp1.second() == 1.3); + compressed_pair cp1b(2, 2.3); + assert(cp1b.first() == 2); + assert(cp1b.second() == 2.3); + swap(cp1, cp1b); + assert(cp1b.first() == 1); + assert(cp1b.second() == 1.3); + assert(cp1.first() == 2); + assert(cp1.second() == 2.3); +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + compressed_pair cp2(2); + assert(cp2.second() == 2); +#endif + compressed_pair cp3(1); + assert(cp3.first() ==1); + compressed_pair cp4; + compressed_pair cp5; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + int i = 0; + compressed_pair cp6(i,i); + assert(cp6.first() == i); + assert(cp6.second() == i); + assert(&cp6.first() == &i); + assert(&cp6.second() == &i); + compressed_pair cp7; + cp7.first(); + double* pd = cp7.second(); +#endif + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair) < sizeof(std::pair))) + value_test(true, (sizeof(compressed_pair >) < sizeof(std::pair >))) + + std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; + std::cin.get(); + return failures; +} + +// +// instanciate some compressed pairs: +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; +template class boost::compressed_pair; + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +// +// now some for which only a few specific members can be instantiated, +// first references: +template double& compressed_pair::first(); +template int& compressed_pair::second(); +template compressed_pair::compressed_pair(int&); +template compressed_pair::compressed_pair(call_traits::param_type,int&); +// +// and then arrays: +#ifndef __BORLANDC__ +template call_traits::reference compressed_pair::second(); +#endif +template call_traits::reference compressed_pair::first(); +template compressed_pair::compressed_pair(const double&); +template compressed_pair::compressed_pair(); +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + + + From d83ea9e52e174aebff49c4291096a5157b8ca6a7 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 27 Jul 2000 13:38:51 +0000 Subject: [PATCH 04/12] Initial HTML commit [SVN r7634] --- call_traits.htm | 738 ++++++++++++++++++++++++++++++++++++++++++++ cast.htm | 148 +++++++++ compressed_pair.htm | 92 ++++++ index.htm | 72 +++++ operators.htm | 598 +++++++++++++++++++++++++++++++++++ type_traits.htm | 588 +++++++++++++++++++++++++++++++++++ utility.htm | 103 +++++++ 7 files changed, 2339 insertions(+) create mode 100644 call_traits.htm create mode 100644 cast.htm create mode 100644 compressed_pair.htm create mode 100644 index.htm create mode 100644 operators.htm create mode 100644 type_traits.htm create mode 100644 utility.htm diff --git a/call_traits.htm b/call_traits.htm new file mode 100644 index 0000000..d0a0fde --- /dev/null +++ b/call_traits.htm @@ -0,0 +1,738 @@ + + + + + + +Call Traits + + + + +

Header +<boost/call_traits.hpp>

+ +

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 partial +specialization, 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.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Existing practice

+

call_traits equivalent

+

Description

+

Notes

+

T
+ (return by value)

+

call_traits<T>::value_type

+
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&
+ (return value)

+

call_traits<T>::reference

+
Defines a type that + represents a reference to type T. Use for functions that + would normally return a T&.

1

+

const T&
+ (return value)

+

call_traits<T>::const_reference

+
Defines a type that + represents a constant reference to type T. Use for + functions that would normally return a const T&.

1

+

const T&
+ (function parameter)

+

call_traits<T>::param_type

+
Defines a type that + represents the "best" way to pass a parameter + of type T to a function.

1,3

+
+ +

Notes:

+ +
    +
  1. If T is already reference type, then call_traits is + defined such that references to + references do not occur (requires partial + specialization).
  2. +
  3. If T is an array type, then call_traits defines 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!).
  4. +
  5. If T is a small built in type or a pointer, then 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).
  6. +
+ +

 

+ +

Copy constructibility

+ +

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

+

-

+

-

+

-

+
+ +

 

+ +

Examples

+ +

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.

+
+ +

 

+ +

Example 1:

+ +

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){}
+
+};
+ +

Example 2 (the reference to reference +problem):

+ +

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.

+ +

Example 3 (the make_pair problem):

+ +

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.

+ +

Example 4 (optimising fill):

+ +

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.

+ +

Rationale

+ +

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 18 June 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/cast.htm b/cast.htm new file mode 100644 index 0000000..2ebb685 --- /dev/null +++ b/cast.htm @@ -0,0 +1,148 @@ + + + + + + +Header boost/cast.hpp Documentation + + + + +

c++boost.gif (8819 bytes)Header +boost/cast.hpp

+

Cast Functions

+

The header boost/cast.hpp +provides polymorphic_cast, polymorphic_downcast, +and numeric_cast template functions designed +to complement the C++ Standard's built-in casts.

+

The program cast_test.cpp can be used to +verify these function templates work as expected.

+

polymorphic_cast was suggested by Bjarne Stroustrup in "The C++ +Programming Language".
+polymorphic_downcast was contributed by Dave +Abrahams.
+numeric_cast
was contributed by Kevlin +Henney.

+

Namespace synopsis

+
+
namespace boost {
+    namespace cast {
+        // all synopsis below included here
+    }
+  using ::boost::cast::polymorphic_cast;
+  using ::boost::cast::polymorphic_downcast;
+  using ::boost::cast::bad_numeric_cast;
+  using ::boost::cast::numeric_cast;
+}
+
+

Polymorphic casts

+

Pointers to polymorphic objects (objects of classes which define at least one +virtual function) are sometimes downcast or crosscast.  Downcasting means +casting from a base class to a derived class.  Crosscasting means casting +across an inheritance hierarchy diagram, such as from one base to the other in a +Y diagram hierarchy.

+

Such casts can be done with old-style casts, but this approach is never to be +recommended.  Old-style casts are sorely lacking in type safety, suffer +poor readability, and are difficult to locate with search tools.

+

The C++ built-in static_cast can be used for efficiently downcasting +pointers to polymorphic objects, but provides no error detection for the case +where the pointer being cast actually points to the wrong derived class. The polymorphic_downcast +template retains the efficiency of static_cast for non-debug +compilations, but for debug compilations adds safety via an assert() that a dynamic_cast +succeeds.  

+

The C++ built-in dynamic_cast can be used for downcasts and crosscasts +of pointers to polymorphic objects, but error notification in the form of a +returned value of 0 is inconvenient to test, or worse yet, easy to forget to +test.  The polymorphic_cast template performs a dynamic_cast, +and throws an exception if the dynamic_cast returns 0.

+

A polymorphic_downcast is preferred when debug-mode tests will cover +100% of the object types possibly cast and when non-debug-mode efficiency is an +issue. If these two conditions are not present, polymorphic_cast is +preferred.  It must also be used for crosscasts.  It does an assert( +dynamic_cast<Derived>(x) == x ) where x is the base pointer, ensuring that +not only is a non-zero pointer returned, but also that it correct in the +presence of multiple inheritance. . Warning:: Because polymorphic_downcast +uses assert(), it violates the One Definition Rule if NDEBUG is inconsistently +defined across translation units.

+

The C++ built-in dynamic_cast must be used to cast references rather +than pointers.  It is also the only cast that can be used to check whether +a given interface is supported; in that case a return of 0 isn't an error +condition.

+

polymorphic_cast and polymorphic_downcast synopsis

+
+
template <class Derived, class Base>
+inline Derived polymorphic_cast(Base* x);
+// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
+// Returns: dynamic_cast<Derived>(x)
+
+template <class Derived, class Base>
+inline Derived polymorphic_downcast(Base* x);
+// Effects: assert( dynamic_cast<Derived>(x) == x );
+// Returns: static_cast<Derived>(x)
+
+

polymorphic_downcast example

+
+
#include <boost/cast.hpp>
+...
+class Fruit { public: virtual ~Fruit(){}; ... };
+class Banana : public Fruit { ... };
+...
+void f( Fruit * fruit ) {
+// ... logic which leads us to believe it is a Banana
+  Banana * banana = boost::polymorphic_downcast<Banana*>(fruit);
+  ...
+
+

numeric_cast

+

A static_cast, implicit_cast or implicit conversion will not +detect failure to preserve range for numeric casts. The numeric_cast +template function are similar to static_cast and certain (dubious) +implicit conversions in this respect, except that they detect loss of numeric +range. An exception is thrown when a runtime value preservation check fails.

+

The requirements on the argument and result types are:

+
+
    +
  • Both argument and result types are CopyConstructible [20.1.3].
  • +
  • Both argument and result types are Numeric, defined by std::numeric_limits<>::is_specialized + being true.
  • +
  • The argument can be converted to the result type using static_cast.
  • +
+
+

numeric_cast synopsis

+
+
class bad_numeric_cast : public std::bad_cast {...};
+
+template<typename Target, typename Source>
+  inline Target numeric_cast(Source arg);
+    // Throws:  bad_numeric_cast unless, in converting arg from Source to Target,
+    //          there is no loss of negative range, and no underflow, and no
+    //          overflow, as determined by std::numeric_limits
+    // Returns: static_cast<Target>(arg)
+
+

numeric_cast example

+
+
#include <boost/cast.hpp>
+using namespace boost::cast;
+
+void ariane(double vx)
+{
+    ...
+    unsigned short dx = numeric_cast<unsigned short>(vx);
+    ...
+}
+
+

numeric_cast rationale

+

The form of the throws condition is specified so that != is not a required +operation.

+
+

Revised  28 June, 2000

+

© Copyright boost.org 1999. 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.

+ + + + diff --git a/compressed_pair.htm b/compressed_pair.htm new file mode 100644 index 0000000..d63af7f --- /dev/null +++ b/compressed_pair.htm @@ -0,0 +1,92 @@ + + + + + + +Header <boost/compressed_pair.hpp> + + + + +

Header +<boost/compressed_pair.hpp>

+ +

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/index.htm b/index.htm new file mode 100644 index 0000000..543abb1 --- /dev/null +++ b/index.htm @@ -0,0 +1,72 @@ + + + + + + +Boost Utility Library + + + + + + + + + + + + + +
c++boost.gif (8819 bytes)HomeLibrariesPeopleFAQMore
+

Boost Utility Library

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HeaderContents
boost/utility.hpp
+
[Documentation]
Class noncopyable plus next() and prior() template + functions.
boost/cast.hpp
+ [Documentation]
polymorphic_cast, implicit_cast, and numeric_cast + function templates. +

[Beta.]

+
boost/operators.hpp
+ [Documentation]
Templates equality_comparable, less_than_comparable, addable, + and the like ease the task of defining comparison and arithmetic + operators, and iterators.
boost/type_traits.hpp
+ [Documentation]
+ [DDJ Article "C++ type traits"]
Template classes that describe the fundamental properties of a type.
boost/call_traits.hpp
+ [Documentation]
Template class call_traits<T>, that defines types used for passing + parameters to and from a proceedure.
boost/compressed_pair.hpp
+ [Documentation]
Template class compressed_pait<T1, T2> which pairs two values + using the empty member optimisation where appropriate.
+

Revised 24 July 2000

+ + + + diff --git a/operators.htm b/operators.htm new file mode 100644 index 0000000..ea57f14 --- /dev/null +++ b/operators.htm @@ -0,0 +1,598 @@ + + + + + + +Header boost/operators.hpp Documentation + + + + +

c++boost.gif (8819 bytes)Header +boost/operators.hpp

+

Header boost/operators.hpp +supplies (in namespace boost) several sets of templates:

+ +

These templates define many global operators in terms of a minimal number of +fundamental operators.

+

Arithmetic Operators

+

If, for example, you declare a class like this:

+
+
class MyInt : boost::operators<MyInt>
+{
+    bool operator<(const MyInt& x) const; 
+    bool operator==(const MyInt& x) const;
+    MyInt& operator+=(const MyInt& x);    
+    MyInt& operator-=(const MyInt& x);    
+    MyInt& operator*=(const MyInt& x);    
+    MyInt& operator/=(const MyInt& x);    
+    MyInt& operator%=(const MyInt& x);    
+    MyInt& operator|=(const MyInt& x);    
+    MyInt& operator&=(const MyInt& x);    
+    MyInt& operator^=(const MyInt& x);    
+    MyInt& operator++();    
+    MyInt& operator--();    
+};
+
+

then the operators<> template adds more than a dozen +additional operators, such as operator>, <=, >=, and +.  Two-argument +forms of the templates are also provided to allow interaction with other +types.

+

Dave Abrahams +started the library and contributed the arithmetic operators in boost/operators.hpp.
+Jeremy Siek +contributed the dereference operators and iterator +helpers in boost/operators.hpp.
+Aleksey Gurtovoy +contributed the code to support base class chaining +while remaining backward-compatible with old versions of the library.
+Beman Dawes +contributed test_operators.cpp.

+

Rationale

+

Overloaded operators for class types typically occur in groups. If you can +write x + y, you probably also want to be able to write x += +y. If you can write x < y, you also want x > y, +x >= y, and x <= y. Moreover, unless your class has +really surprising behavior, some of these related operators can be defined in +terms of others (e.g. x >= y <=> !(x < y)). +Replicating this boilerplate for multiple classes is both tedious and +error-prone. The boost/operators.hpp +templates help by generating operators for you at namespace scope based on other +operators you've defined in your class.

+ +

Two-Argument Template Forms

+
+

The arguments to a binary operator commonly have identical types, but it is +not unusual to want to define operators which combine different types. For example, +one might want to multiply a mathematical vector by a scalar. The two-argument +template forms of the arithmetic operator templates are supplied for this +purpose. When applying the two-argument form of a template, the desired return +type of the operators typically determines which of the two types in question +should be derived from the operator template. For example, if the result of T + U +is of type T, then T (not U) should be +derived from addable<T,U>. The comparison templates less_than_comparable<> +and equality_comparable<> +are exceptions to this guideline, since the return type of the operators they +define is bool.

+

On compilers which do not support partial specialization, the two-argument +forms must be specified by using the names shown below with the trailing '2'. +The single-argument forms with the trailing '1' are provided for +symmetry and to enable certain applications of the base +class chaining technique.

+

Arithmetic operators table

+

The requirements for the types used to instantiate operator templates are +specified in terms of expressions which must be valid and by the return type of +the expression. In the following table t and t1 are +values of type T, and u is a value of type U. +Every template in the library other than operators<> +and operators2<> has an additional +optional template parameter B which is not shown in the table, but +is explained below

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
templatetemplate will supplyRequirements
operators<T>All the other <T> templates in this table.All the <T> requirements in this table.
operators<T,U>
+ operators2<T,U>
All the other <T,U> templates in this table, plus incrementable<T> + and decrementable<T>.All the <T,U> requirements in this table*, + plus incrementable<T> and decrementable<T>.
less_than_comparable<T>
+ less_than_comparable1<T>
bool operator>(const T&, const T&) 
+ bool operator<=(const T&, const T&)
+ bool operator>=(const T&, const T&)
t<t1. Return convertible to bool
less_than_comparable<T,U>
+ less_than_comparable2<T,U>
bool operator<=(const T&, const U&)
+ bool operator>=(const T&, const U&)
+ bool operator>(const U&, const T&) 
+ bool operator<(const U&, const T&) 
+ bool operator<=(const U&, const T&)
+ bool operator>=(const U&, const T&)
t<u. Return convertible to bool
+ t>u. Return convertible to bool
equality_comparable<T>
+ equality_comparable1<T>
bool operator!=(const T&, const T&)t==t1. Return convertible to bool
equality_comparable<T,U>
+ equality_comparable2<T,U>
friend bool operator==(const U&, const T&)
+ friend bool operator!=(const U&, const T&)
+ friend bool operator!=( const T&, const U&)
t==u. Return convertible to bool
addable<T>
+ addable1<T>
T operator+(T, const T&)t+=t1. Return convertible to T
addable<T,U>
+ addable2<T,U>
T operator+(T, const U&)
+ T operator+(const U&, T )
t+=u. Return convertible to T
subtractable<T>
+ subtractable1<T>
T operator-(T, const T&)t-=t1. Return convertible to T
subtractable<T,U>
+ subtractable2<T,U>
T operator-(T, const U&)t-=u. Return convertible to T
multipliable<T>
+ multipliable1<T>
T operator*(T, const T&)t*=t1. Return convertible to T
multipliable<T,U>
+ multipliable2<T,U>
T operator*(T, const U&)
+ T operator*(const U&, T )
t*=u. Return convertible to T
dividable<T>
+ dividable1<T>
T operator/(T, const T&)t/=t1. Return convertible to T
dividable<T,U>
+ dividable2<T,U>
T operator/(T, const U&)t/=u. Return convertible to T
modable<T>
+ modable1<T>
T operator%(T, const T&)t%=t1. Return convertible to T
modable<T,U>
+ modable2<T,U>
T operator%(T, const U&)t%=u. Return convertible to T
orable<T>
+ orable1<T>
T operator|(T, const T&)t|=t1. Return convertible to T
orable<T,U>
+ orable2<T,U>
T operator|(T, const U&)
+ T operator|(const U&, T )
t|=u. Return convertible to T
andable<T>
+ andable1<T>
T operator&(T, const T&)t&=t1. Return convertible to T
andable<T,U>
+ andable2<T,U>
T operator&(T, const U&)
+ T operator&(const U&, T)
t&=u. Return convertible to T
xorable<T>
+ xorable1<T>
T operator^(T, const T&)t^=t1. Return convertible to T
xorable<T,U>
+ xorable2<T,U>
T operator^(T, const U&)
+ T operator^(const U&, T )
t^=u. Return convertible to T
incrementable<T>
+ incrementable1<T>
T operator++(T& x, int)T temp(x); ++x; return temp;
+ Return convertible to T
decrementable<T>
+ decrementable1<T>
T operator--(T& x, int)T temp(x); --x; return temp;
+ Return convertible to T
+
+Portability Note: many compilers (e.g. MSVC6.3, +GCC 2.95.2) will not enforce the requirements in this table unless the +operations which depend on them are actually used. This is not +standard-conforming behavior. If you are trying to write portable code it is +important not to rely on this bug. In particular, it would be convenient to +derive all your classes which need binary operators from the operators<> +and operators2<> templates, +regardless of whether they implement all the requirements in the table. Even if +this works with your compiler today, it may not work tomorrow. +

Base Class Chaining and Object Size

+

Every template listed in the table except operators<> +and operators2<> has an additional +optional template parameter B.  If supplied, B +must be a class type; the resulting class will be publicly derived from B. This +can be used to avoid the object size bloat commonly associated with multiple +empty base classes (see the note for users of older +versions below for more details). To provide support for several groups of +operators, use the additional parameter to chain operator templates into a +single-base class hierarchy, as in the following example.

+

Caveat: to chain to a base class which is not a boost operator +template when using the single-argument form of a +boost operator template, you must specify the operator template with the +trailing '1' in its name. Otherwise the library will assume you +mean to define a binary operation combining the class you intend to use as a +base class and the class you're deriving.

+

Borland users: even single-inheritance seems to cause an increase in +object size in some cases. If you are not defining a template, you may get +better object-size performance by avoiding derivation altogether, and instead +explicitly instantiating the operator template as follows: +

+    class myclass // lose the inheritance...
+    {
+        //...
+    };
+    // explicitly instantiate the operators I need.
+    template class less_than_comparable<myclass>;
+    template class equality_comparable<myclass>;
+    template class incrementable<myclass>;
+    template class decrementable<myclass>;
+    template class addable<myclass,long>;
+    template class subtractable<myclass,long>;
+
+
+

Usage example

+
+
template <class T>
+class point    // note: private inheritance is OK here!
+    : boost::addable< point<T>          // point + point
+    , boost::subtractable< point<T>     // point - point
+    , boost::dividable2< point<T>, T    // point / T
+    , boost::multipliable2< point<T>, T // point * T, T * point
+      > > > >
+{
+public:
+    point(T, T);
+    T x() const;
+    T y() const;
+
+    point operator+=(const point&);
+    // point operator+(point, const point&) automatically
+    // generated by addable.
+
+    point operator-=(const point&);
+    // point operator-(point, const point&) automatically
+    // generated by subtractable.
+
+    point operator*=(T);
+    // point operator*(point, const T&) and
+    // point operator*(const T&, point) auto-generated
+    // by multipliable.
+
+    point operator/=(T);
+    // point operator/(point, const T&) auto-generated
+    // by dividable.
+private:
+    T x_;
+    T y_;
+};
+
+// now use the point<> class:
+
+template <class T>
+T length(const point<T> p)
+{
+    return sqrt(p.x()*p.x() + p.y()*p.y());
+}
+
+const point<float> right(0, 1);
+const point<float> up(1, 0);
+const point<float> pi_over_4 = up + right;
+const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);
+

Arithmetic operators demonstration and test program

+

The operators_test.cpp +program demonstrates the use of the arithmetic operator templates, and can also +be used to verify correct operation.

+

The test program has been compiled and run successfully with: 

+
    +
  • GCC 2.95.2 +
  • GCC 2.95.2 / STLport 4.0b8. +
  • Metrowerks Codewarrior 5.3 +
  • KAI C++ 3.3 +
  • Microsoft Visual C++ 6.0 SP3. +
  • Microsoft Visual C++ 6.0 SP3 / STLport 4.0b8.
  • +
+

Dereference operators and iterator helpers

+

The iterator helper templates ease the task +of creating a custom iterator. Similar to arithmetic types, a complete iterator +has many operators that are "redundant" and can be implemented in +terms of the core set of operators.

+

The dereference operators were motivated by the iterator +helpers, but are often useful in non-iterator contexts as well. Many of the +redundant iterator operators are also arithmetic operators, so the iterator +helper classes borrow many of the operators defined above. In fact, only two new +operators need to be defined! (the pointer-to-member operator-> +and the subscript operator[]). +

Notation

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tis the user-defined type for which the operations are + being supplied.
Vis the type which the resulting dereferenceable + type "points to", or the value_type of the custom + iterator.
Dis the type used to index the resulting indexable + type or the difference_type of the custom iterator.
Pis a type which can be dereferenced to access V, + or the pointer type of the custom iterator.
Ris the type returned by indexing the indexable + type or the reference type of the custom iterator.
iis short for static_cast<const T&>(*this), + where this is a pointer to the helper class.
+ Another words, i should be an object of the custom iterator + type.
x,x1,x2are objects of type T.
nis an object of type D.
+

The requirements for the types used to instantiate the dereference operators +and iterator helpers are specified in terms of expressions which must be valid +and their return type. 

+

Dereference operators

+

The dereference operator templates in this table all accept an optional +template parameter (not shown) to be used for base class +chaining. + + + + + + + + + + + + + + + + + + +
templatetemplate will supplyRequirements
dereferenceable<T,P>P operator->() const(&*i.). Return convertible to P.
indexable<T,D,R>R operator[](D n) const*(i + n). Return of type R.
+

Iterator helpers

+

There are three separate iterator helper classes, each for a different +category of iterator. Here is a summary of the core set of operators that the +custom iterator must define, and the extra operators that are created by the +helper classes. For convenience, the helper classes also fill in all of the +typedef's required of iterators by the C++ standard (iterator_category, +value_type, etc.).

+ + + + + + + + + + + + + + + + + + + + + + + +
templatetemplate will supplyRequirements
forward_iterator_helper
+ <T,V,D,P,R>
bool operator!=(const T& x1, const T& x2)
+ T operator++(T& x, int)
+ V* operator->() const
+
x1==x2. Return convertible to bool
+ T temp(x); ++x; return temp;
+ (&*i.). Return convertible to V*.
bidirectional_iterator_helper
+ <T,V,D,P,R>
Same as above, plus
+ T operator--(T& x, int)
Same as above, plus
+ T temp(x); --x; return temp;
random_access_iterator_helper
+ <T,V,D,P,R>
Same as above, plus
+ T operator+(T x, const D&)
+ T operator+(const D& n, T x)
+ T operator-(T x, const D& n)
+ R operator[](D n) const
+ bool operator>(const T& x1, const T& x2) 
+ bool operator<=(const T& x1, const T& x2)
+ bool operator>=(const T& x1, const T& x2)
Same as above, plus
+ x+=n. Return convertible to T
+ x-=n. Return convertible to T
+ x1<x2. Return convertible to bool
+ And to satisfy RandomAccessIterator:
+ x1-x2. Return convertible to D
+

Iterator demonstration and test program

+

The iterators_test.cpp +program demonstrates the use of the iterator templates, and can also be used to +verify correct operation. The following is the custom iterator defined in the +test program. It demonstrates a correct (though trivial) implementation of the +core operations that must be defined in order for the iterator helpers to +"fill in" the rest of the iterator operations.

+
+
template <class T, class R, class P>
+struct test_iter
+  : public boost::random_access_iterator_helper<
+     test_iter<T,R,P>, T, std::ptrdiff_t, P, R>
+{
+  typedef test_iter self;
+  typedef R Reference;
+  typedef std::ptrdiff_t Distance;
+
+public:
+  test_iter(T* i) : _i(i) { }
+  test_iter(const self& x) : _i(x._i) { }
+  self& operator=(const self& x) { _i = x._i; return *this; }
+  Reference operator*() const { return *_i; }
+  self& operator++() { ++_i; return *this; }
+  self& operator--() { --_i; return *this; }
+  self& operator+=(Distance n) { _i += n; return *this; }
+  self& operator-=(Distance n) { _i -= n; return *this; }
+  bool operator==(const self& x) const { return _i == x._i; }
+  bool operator<(const self& x) const { return _i < x._i; }
+  friend Distance operator-(const self& x, const self& y) {
+    return x._i - y._i; 
+  }
+protected:
+  T* _i;
+};
+
+

It has been compiled and run successfully with:

+
    +
  • GCC 2.95.2 +
  • Metrowerks Codewarrior 5.2 +
  • Microsoft Visual C++ 6.0 SP3
  • +
+

Jeremy Siek +contributed the iterator operators and helpers.  He also contributed iterators_test.cpp

+
+

Note for users of older versions

+

The changes in the library interface and recommended +usage were motivated by some practical issues described below. The new +version of the library is still backward-compatible with the former one (so +you're not forced change any existing code), but the old usage is +deprecated. Though it was arguably simpler and more intuitive than using base +class chaining, it has been discovered that the old practice of deriving +from multiple operator templates can cause the resulting classes to be much +larger than they should be. Most modern C++ compilers significantly bloat the +size of classes derived from multiple empty base classes, even though the base +classes themselves have no state. For instance, the size of point<int> +from the example above was 12-24 bytes on various compilers +for the Win32 platform, instead of the expected 8 bytes. +

Strictly speaking, it was not the library's fault - the language rules allow +the compiler to apply the empty base class optimization in that situation. In +principle an arbitrary number of empty base classes can be allocated at the same +offset, provided that none of them have a common ancestor (see section 10.5 [class.derived], +par. 5 of the standard). But the language definition also doesn't require +implementations to do the optimization, and few if any of today's compilers +implement it when multiple inheritance is involved. What's worse, it is very +unlikely that implementors will adopt it as a future enhancement to existing +compilers, because it would break binary compatibility between code generated by +two different versions of the same compiler. As Matt Austern said, "One of +the few times when you have the freedom to do this sort of thing is when you're +targeting a new architecture...". On the other hand, many common compilers +will use the empty base optimization for single inheritance hierarchies.

+

Given the importance of the issue for the users of the library (which aims to +be useful for writing light-weight classes like MyInt or point<>), +and the forces described above, we decided to change the library interface so +that the object size bloat could be eliminated even on compilers that support +only the simplest form of the empty base class optimization. The current library +interface is the result of those changes. Though the new usage is a bit more +complicated than the old one, we think it's worth it to make the library more +useful in real world. Alexy Gurtovoy contributed the code which supports the new +usage idiom while allowing the library remain backward-compatible.

+
+

Revised 28 Jun 2000 +

+

© Copyright David Abrahams and Beman Dawes 1999-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.

+ + + + diff --git a/type_traits.htm b/type_traits.htm new file mode 100644 index 0000000..dae21d7 --- /dev/null +++ b/type_traits.htm @@ -0,0 +1,588 @@ + + + + + + +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
+   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).

+ +

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.

P

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

P

+
is_same<T,U>::valueTrue if T and U are the same + type.

P

+
+ +

 

+ +

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

P

+
is_member_pointer<T>::valueTrue if T is a pointer to a + non-static class member (3.9.2 p1 and 8.3.1).

P

+
is_reference<T>::valueTrue if T is a reference + type (3.9.2 p1 and 8.3.2).

P

+
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 - as a result will + not compile when passed an enumerated type unless there + is compiler support for is_enum.

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 08th 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/utility.htm b/utility.htm new file mode 100644 index 0000000..2f0272e --- /dev/null +++ b/utility.htm @@ -0,0 +1,103 @@ + + + + +Header boost/utility.hpp Documentation + + + + +

c++boost.gif (8819 bytes)Header +boost/utility.hpp

+ +

The entire contents of the header <boost/utility.hpp> + are in namespace boost.

+ +

Contents

+ + +

Template functions next() and prior()

+ +

Certain data types, such as the C++ Standard Library's forward and +bidirectional iterators, do not provide addition and subtraction via operator+() +or operator-().  This means that non-modifying computation of the next or +prior value requires a temporary, even though operator++() or operator--() is +provided.  It also means that writing code like itr+1 inside a +template restricts the iterator category to random access iterators.

+ +

The next() and prior() functions provide a simple way around these problems:

+ +
+ +
template <class T>
+T next(T x) { return ++x; }
+
+template <class X>
+T prior(T x) { return --x; }
+ +
+ +

Usage is simple:

+ +
+ +
const std::list<T>::iterator p = get_some_iterator();
+const std::list<T>::iterator prev = boost::prior(p);
+ +
+ +

Contributed by Dave Abrahams.

+ +

Class noncopyable

+ +

Class noncopyable is a base class.  Derive your own class from noncopyable +when you want to prohibit copy construction and copy assignment.

+ +

Some objects, particularly those which hold complex resources like files or +network connections, have no sensible copy semantics.  Sometimes there are +possible copy semantics, but these would be of very limited usefulness and be +very difficult to implement correctly.  Sometimes you're implementing a class that doesn't need to be copied +just yet and you don't want to take the time to write the appropriate functions.  +Deriving from noncopyable will prevent the otherwise implicitly-generated +functions (which don't have the proper semantics) from becoming a trap for other programmers.

+ +

The traditional way to deal with these is to declare a private copy constructor and copy assignment, and then +document why this is done.  But deriving from noncopyable is simpler +and clearer, and doesn't require additional documentation.

+ +

The program noncopyable_test.cpp can be +used to verify class noncopyable works as expected. It has have been run successfully under +GCC 2.95, Metrowerks +CodeWarrior 5.0, and Microsoft Visual C++ 6.0 sp 3.

+ +

Contributed by Dave Abrahams.

+ +

Example

+
+
// inside one of your own headers ...
+#include <boost/utility.hpp>
+
+class ResourceLadenFileSystem : noncopyable {
+...
+
+ +

Rationale

+

Class noncopyable has protected constructor and destructor members to +emphasize that it is to be used only as a base class.  Dave Abrahams notes +concern about the effect on compiler optimization of adding (even trivial inline) +destructor declarations. He says "Probably this concern is misplaced, because +noncopyable will be used mostly for classes which own resources and thus have non-trivial destruction semantics."

+
+

Revised  26 January, 2000 +

+

© Copyright boost.org 1999. 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.

+ + From b231894f1bc5ce40524d1968d2e3bb57cd2b7fdb Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 27 Jul 2000 14:21:30 +0000 Subject: [PATCH 05/12] Test HTML commit after FrontPage change. No actual content changed. [SVN r7639] --- index.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.htm b/index.htm index 543abb1..9f73fff 100644 --- a/index.htm +++ b/index.htm @@ -65,7 +65,7 @@ using the empty member optimisation where appropriate. -

Revised 24 July 2000

+

Revised 27 July 2000

From ba6228757604427139e643aa89db8faecd708426 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 27 Jul 2000 14:46:23 +0000 Subject: [PATCH 06/12] Initial commit [SVN r7646] --- c++_type_traits.htm | 489 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 489 insertions(+) create mode 100644 c++_type_traits.htm diff --git a/c++_type_traits.htm b/c++_type_traits.htm new file mode 100644 index 0000000..3cbb786 --- /dev/null +++ b/c++_type_traits.htm @@ -0,0 +1,489 @@ + + + + + + +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

+ + + + From 767b61a254de244164e7f8e5979d114803f17bed Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 27 Jul 2000 14:46:43 +0000 Subject: [PATCH 07/12] Minor format fix [SVN r7647] --- index.htm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.htm b/index.htm index 9f73fff..8de3155 100644 --- a/index.htm +++ b/index.htm @@ -48,9 +48,9 @@ boost/type_traits.hpp
- [Documentation]
- [DDJ Article "C++ type traits"] - Template classes that describe the fundamental properties of a type. + [Documentation] + Template classes that describe the fundamental properties of a type. [DDJ + Article "C++ type traits"] boost/call_traits.hpp
From e52916acf2338c4d9d18de2ace90b1a7a5cdb9f0 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Sat, 29 Jul 2000 11:39:42 +0000 Subject: [PATCH 08/12] minor compiler compatability fixes [SVN r7661] --- call_traits_test.cpp | 76 +++++++++++++++++++++++----------------- compressed_pair_test.cpp | 18 ++++++---- type_traits_test.cpp | 6 ++++ 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/call_traits_test.cpp b/call_traits_test.cpp index c89169f..d0db895 100644 --- a/call_traits_test.cpp +++ b/call_traits_test.cpp @@ -295,37 +295,47 @@ int main() template struct call_traits_test { - static void assert_construct(boost::call_traits::param_type val); + typedef ::boost::call_traits ct; + typedef typename ct::param_type param_type; + typedef typename ct::reference reference; + typedef typename ct::const_reference const_reference; + typedef typename ct::value_type value_type; + static void assert_construct(param_type val); }; template -void call_traits_test::assert_construct(boost::call_traits::param_type val) +void call_traits_test::assert_construct(typename call_traits_test::param_type val) { // // this is to check that the call_traits assertions are valid: T t(val); - boost::call_traits::value_type v(t); - boost::call_traits::reference r(t); - boost::call_traits::const_reference cr(t); - boost::call_traits::param_type p(t); - boost::call_traits::value_type v2(v); - boost::call_traits::value_type v3(r); - boost::call_traits::value_type v4(p); - boost::call_traits::reference r2(v); - boost::call_traits::reference r3(r); - boost::call_traits::const_reference cr2(v); - boost::call_traits::const_reference cr3(r); - boost::call_traits::const_reference cr4(cr); - boost::call_traits::const_reference cr5(p); - boost::call_traits::param_type p2(v); - boost::call_traits::param_type p3(r); - boost::call_traits::param_type p4(p); + value_type v(t); + reference r(t); + const_reference cr(t); + param_type p(t); + value_type v2(v); + value_type v3(r); + value_type v4(p); + reference r2(v); + reference r3(r); + const_reference cr2(v); + const_reference cr3(r); + const_reference cr4(cr); + const_reference cr5(p); + param_type p2(v); + param_type p3(r); + param_type p4(p); } #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct call_traits_test { - static void assert_construct(boost::call_traits::param_type val); + typedef ::boost::call_traits ct; + typedef typename ct::param_type param_type; + typedef typename ct::reference reference; + typedef typename ct::const_reference const_reference; + typedef typename ct::value_type value_type; + static void assert_construct(param_type val); }; template @@ -334,23 +344,23 @@ void call_traits_test::assert_construct(boost::call_traits::param_ty // // this is to check that the call_traits assertions are valid: T t; - boost::call_traits::value_type v(t); - boost::call_traits::value_type v5(val); - boost::call_traits::reference r = t; - boost::call_traits::const_reference cr = t; - boost::call_traits::reference r2 = r; + value_type v(t); + value_type v5(val); + reference r = t; + const_reference cr = t; + reference r2 = r; #ifndef __BORLANDC__ // C++ Builder buglet: - boost::call_traits::const_reference cr2 = r; + const_reference cr2 = r; #endif - boost::call_traits::param_type p(t); - boost::call_traits::value_type v2(v); - boost::call_traits::const_reference cr3 = cr; - boost::call_traits::value_type v3(r); - boost::call_traits::value_type v4(p); - boost::call_traits::param_type p2(v); - boost::call_traits::param_type p3(r); - boost::call_traits::param_type p4(p); + param_type p(t); + value_type v2(v); + const_reference cr3 = cr; + value_type v3(r); + value_type v4(p); + param_type p2(v); + param_type p3(r); + param_type p4(p); } #endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/compressed_pair_test.cpp b/compressed_pair_test.cpp index ebbaa78..c8ab32f 100644 --- a/compressed_pair_test.cpp +++ b/compressed_pair_test.cpp @@ -1,9 +1,3 @@ -// 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. #include #include @@ -24,6 +18,7 @@ unsigned test_count = 0; #define value_test(v, x) ++test_count;\ if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} +#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;\ @@ -110,12 +105,21 @@ int main() // // instanciate some compressed pairs: +#ifdef __MWERKS__ +template class compressed_pair; +template class compressed_pair; +template class compressed_pair; +template class compressed_pair; +template class compressed_pair; +template class compressed_pair; +#else template class boost::compressed_pair; template class boost::compressed_pair; template class boost::compressed_pair; template class boost::compressed_pair; template class boost::compressed_pair; template class boost::compressed_pair; +#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION // @@ -127,12 +131,14 @@ template compressed_pair::compressed_pair(int&); template compressed_pair::compressed_pair(call_traits::param_type,int&); // // and then arrays: +#ifndef __MWERKS__ #ifndef __BORLANDC__ template call_traits::reference compressed_pair::second(); #endif template call_traits::reference compressed_pair::first(); template compressed_pair::compressed_pair(const double&); template compressed_pair::compressed_pair(); +#endif // __MWERKS__ #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/type_traits_test.cpp b/type_traits_test.cpp index b50892a..8c0e460 100644 --- a/type_traits_test.cpp +++ b/type_traits_test.cpp @@ -30,6 +30,7 @@ unsigned test_count = 0; #define value_test(v, x) ++test_count;\ if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} +#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(is_same::value == false){\ @@ -438,7 +439,12 @@ int main() value_test(false, is_empty::value) value_test(false, is_empty::value) value_test(false, is_empty::value) +#ifdef __MWERKS__ + // apparent compiler bug causes this to fail to compile: + 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(false, is_empty::value) From 2086542bfbbcf7f2d22b64e4a3b56dc168449471 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Sun, 30 Jul 2000 10:33:53 +0000 Subject: [PATCH 09/12] replaced lost copyright declaration [SVN r7662] --- compressed_pair_test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compressed_pair_test.cpp b/compressed_pair_test.cpp index c8ab32f..c34aa17 100644 --- a/compressed_pair_test.cpp +++ b/compressed_pair_test.cpp @@ -1,3 +1,9 @@ + // 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. #include #include @@ -144,3 +150,4 @@ template compressed_pair::compressed_pair(); + From daf7829ffa8b8c8e816dd6b767fe010d0e52763e Mon Sep 17 00:00:00 2001 From: John Maddock Date: Wed, 2 Aug 2000 10:58:59 +0000 Subject: [PATCH 10/12] type traits update [added is_convertible and alignment_of] [SVN r7675] --- call_traits_test.cpp | 39 ++----- compressed_pair_test.cpp | 32 +----- include/boost/detail/call_traits.hpp | 3 + include/boost/detail/compressed_pair.hpp | 2 + include/boost/detail/ob_call_traits.hpp | 1 + include/boost/detail/ob_compressed_pair.hpp | 1 + type_traits.htm | 88 +++++++++++----- type_traits_test.cpp | 111 +++++++++++++++----- type_traits_test.hpp | 106 +++++++++++++++++++ 9 files changed, 271 insertions(+), 112 deletions(-) create mode 100644 type_traits_test.hpp diff --git a/call_traits_test.cpp b/call_traits_test.cpp index d0db895..4bb66b6 100644 --- a/call_traits_test.cpp +++ b/call_traits_test.cpp @@ -1,3 +1,11 @@ + // 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 #include #include @@ -6,12 +14,7 @@ #include #include -#ifdef __BORLANDC__ -// turn off some warnings, the way we do the tests will generate a *lot* of these -// this is a result of the tests not call_traits itself.... -#pragma option -w-8004 -w-ccc -w-rch -w-eff -w-aus -#endif - +#include "type_traits_test.hpp" // // struct contained models a type that contains a type (for example std::pair) // arrays are contained by value, and have to be treated as a special case: @@ -178,30 +181,6 @@ struct UDT bool operator == (const UDT& v){ return v.i_ == i_; } }; -// -// define tests here -unsigned failures = 0; -unsigned test_count = 0; - -#define value_test(v, x) ++test_count;\ - if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -#define type_test(v, x) ++test_count;\ - if(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 - int main() { checker c1; diff --git a/compressed_pair_test.cpp b/compressed_pair_test.cpp index c34aa17..ba6d81d 100644 --- a/compressed_pair_test.cpp +++ b/compressed_pair_test.cpp @@ -5,43 +5,17 @@ // 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 + #include #include #include #include +#include "type_traits_test.hpp" using namespace boost; -#ifdef __BORLANDC__ -#pragma option -w-ccc -w-rch -w-eff -w-aus -#endif - -// -// define tests here -unsigned failures = 0; -unsigned test_count = 0; - -#define value_test(v, x) ++test_count;\ - if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} -#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(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 - struct empty_POD_UDT{}; struct empty_UDT { diff --git a/include/boost/detail/call_traits.hpp b/include/boost/detail/call_traits.hpp index 93dc7b1..8d02eca 100644 --- a/include/boost/detail/call_traits.hpp +++ b/include/boost/detail/call_traits.hpp @@ -6,6 +6,9 @@ // See http://www.boost.org for most recent version including documentation. +// call_traits: defines typedefs for function usage +// (see libs/utility/call_traits.htm) + /* Release notes: 23rd July 2000: Fixed array specialization. (JM) diff --git a/include/boost/detail/compressed_pair.hpp b/include/boost/detail/compressed_pair.hpp index a4b3390..87c2449 100644 --- a/include/boost/detail/compressed_pair.hpp +++ b/include/boost/detail/compressed_pair.hpp @@ -6,6 +6,8 @@ // See http://www.boost.org for most recent version including documentation. +// compressed_pair: pair that "compresses" empty members +// (see libs/utility/compressed_pair.htm) // // JM changes 25 Jan 2000: // Removed default arguments from compressed_pair_switch to get diff --git a/include/boost/detail/ob_call_traits.hpp b/include/boost/detail/ob_call_traits.hpp index 332931e..54f2739 100644 --- a/include/boost/detail/ob_call_traits.hpp +++ b/include/boost/detail/ob_call_traits.hpp @@ -7,6 +7,7 @@ // See http://www.boost.org for most recent version including documentation. // // Crippled version for crippled compilers: +// see libs/utility/call_traits.htm // #ifndef BOOST_OB_CALL_TRAITS_HPP #define BOOST_OB_CALL_TRAITS_HPP diff --git a/include/boost/detail/ob_compressed_pair.hpp b/include/boost/detail/ob_compressed_pair.hpp index ce7e064..994c974 100644 --- a/include/boost/detail/ob_compressed_pair.hpp +++ b/include/boost/detail/ob_compressed_pair.hpp @@ -5,6 +5,7 @@ // warranty, and with no claim as to its suitability for any purpose. // See http://www.boost.org for most recent version including documentation. +// see libs/utility/compressed_pair.hpp // /* Release notes: 23rd July 2000: diff --git a/type_traits.htm b/type_traits.htm index dae21d7..66c5370 100644 --- a/type_traits.htm +++ b/type_traits.htm @@ -25,6 +25,7 @@ divided up into the following sections:

Fundamental type operations
 Fundamental type properties
+   Miscellaneous
    cv-Qualifiers
    Fundamental Types
    Compound Types
@@ -37,7 +38,7 @@ divided up into the following sections:

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

- +
@@ -108,39 +109,75 @@ indicated transformation on type T.

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

+

Miscellaneous

+ +

Expression.

+ + + + + + + + + + + + + + + + + + + + +

Expression

+

Description

+

Compiler

+
is_same<T,U>::value
+

True if T and U are the + same type.

+

P

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

+

Expression.

Description.

+

Description.

Compiler.

+

Compiler.

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

P

+

P

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

P

-
is_same<T,U>::valueTrue if T and U are the same - type.

P

+

P

@@ -152,7 +189,7 @@ on a type (see 3.93).

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

- +
@@ -291,7 +328,7 @@ these are closely based on the section 3.9 of the C++ Standard.

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

-

Expression.

+
@@ -365,7 +402,7 @@ as defined by the Standard. 

is true then class_name<cv-qualified-T>::value will also be true.

-

Expression

+
@@ -420,9 +457,10 @@ will also be true.

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 - as a result will - not compile when passed an enumerated type unless there - is compiler support for is_enum. + 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. @@ -582,7 +620,7 @@ Hinnant and John Maddock.

Maintained by John Maddock, the latest version of this file can be found at www.boost.org, and the boost +href="http://www.boost.org/">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 index 8c0e460..719b2d1 100644 --- a/type_traits_test.cpp +++ b/type_traits_test.cpp @@ -4,7 +4,11 @@ // 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: + 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 @@ -16,37 +20,10 @@ #include #include +#include "type_traits_test.hpp" using namespace boost; -#ifdef __BORLANDC__ -#pragma option -w-ccc -w-rch -w-eff -w-aus -#endif - -// -// define tests here -unsigned failures = 0; -unsigned test_count = 0; - -#define value_test(v, x) ++test_count;\ - if(v != x){++failures; std::cout << "checking value of " << #x << "...failed" << std::endl;} -#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(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(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 - // Since there is no compiler support, we should specialize: // is_enum for all enumerations (is_enum implies is_POD) // is_union for all unions @@ -160,6 +137,33 @@ template <> struct is_POD } #endif +class Base { }; + +class Deriverd : public Base { }; + +class NonDerived { }; + +enum enum1 +{ + one_,two_ +}; + +enum enum2 +{ + three_,four_ +}; + +struct VB +{ + virtual ~VB(){}; +}; + +struct VD : VB +{ + ~VD(){}; +}; + + // 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 @@ -530,6 +534,57 @@ int main() 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(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(false, (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)... press any key to exit"; std::cin.get(); return failures; diff --git a/type_traits_test.hpp b/type_traits_test.hpp new file mode 100644 index 0000000..3e0b44e --- /dev/null +++ b/type_traits_test.hpp @@ -0,0 +1,106 @@ + // 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 + +// +// 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 ) + + +#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;} +#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 +unsigned failures = 0; +unsigned test_count = 0; + +// +// 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 From 5b06dd0d0dea67328838ccbb8fd098356b1805f4 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Thu, 3 Aug 2000 15:26:16 +0000 Subject: [PATCH 11/12] 1.17.0 release candidate runup [SVN r7683] --- operators.htm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/operators.htm b/operators.htm index ea57f14..0062e59 100644 --- a/operators.htm +++ b/operators.htm @@ -11,7 +11,7 @@

c++boost.gif (8819 bytes)Header boost/operators.hpp

-

Header boost/operators.hpp +

Header boost/operators.hpp supplies (in namespace boost) several sets of templates:

Expression

PCD