mirror of
https://github.com/boostorg/utility.git
synced 2025-05-09 15:04:00 +00:00
Initial commit after public review (note change in library name per review)
[SVN r8516]
This commit is contained in:
parent
cba48df8e3
commit
6a0c3e92a0
148
cast.htm
148
cast.htm
@ -1,148 +0,0 @@
|
|||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
||||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
|
||||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
|
||||||
<title>Header boost/cast.hpp Documentation</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000">
|
|
||||||
|
|
||||||
<h1><img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align="center" width="277" height="86">Header
|
|
||||||
<a href="../../boost/cast.hpp">boost/cast.hpp</a></h1>
|
|
||||||
<h2><a name="Cast Functions">Cast Functions</a></h2>
|
|
||||||
<p>The <code>header <a href="../../boost/cast.hpp">boost/cast.hpp</a></code>
|
|
||||||
provides <a href="#Polymorphic_cast"><b>polymorphic_cast</b></a>, <a href="#Polymorphic_cast"><b>polymorphic_downcast</b></a>,
|
|
||||||
and <a href="#numeric_cast"><b>numeric_cast</b></a> template functions designed
|
|
||||||
to complement the C++ Standard's built-in casts.</p>
|
|
||||||
<p>The program <a href="cast_test.cpp">cast_test.cpp</a> can be used to
|
|
||||||
verify these function templates work as expected.</p>
|
|
||||||
<p><b>polymorphic_cast</b> was suggested by Bjarne Stroustrup in "The C++
|
|
||||||
Programming Language".<br>
|
|
||||||
<b>polymorphic_downcast</b> was contributed by <a href="../../people/dave_abrahams.htm">Dave
|
|
||||||
Abrahams</a>.<b><br>
|
|
||||||
numeric_cast</b> was contributed by <a href="../../people/kevlin_henney.htm">Kevlin
|
|
||||||
Henney</a>.</p>
|
|
||||||
<h3>Namespace synopsis</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>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;
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3><a name="Polymorphic_cast">Polymorphic casts</a></h3>
|
|
||||||
<p>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
|
|
||||||
<b>Y</b> diagram hierarchy.</p>
|
|
||||||
<p>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.</p>
|
|
||||||
<p>The C++ built-in <b>static_cast</b> 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 <b>polymorphic_downcast</b>
|
|
||||||
template retains the efficiency of <b>static_cast</b> for non-debug
|
|
||||||
compilations, but for debug compilations adds safety via an assert() that a <b>dynamic_cast</b>
|
|
||||||
succeeds. <b> </b></p>
|
|
||||||
<p>The C++ built-in <b>dynamic_cast</b> 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 <b>polymorphic_cast</b> template performs a <b>dynamic_cast</b>,
|
|
||||||
and throws an exception if the <b>dynamic_cast</b> returns 0.</p>
|
|
||||||
<p>A <b>polymorphic_downcast</b> 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, <b>polymorphic_cast</b> 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. .<b> Warning:</b>: Because <b>polymorphic_downcast</b>
|
|
||||||
uses assert(), it violates the One Definition Rule if NDEBUG is inconsistently
|
|
||||||
defined across translation units.</p>
|
|
||||||
<p>The C++ built-in <b>dynamic_cast</b> 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.</p>
|
|
||||||
<h3>polymorphic_cast and polymorphic_downcast synopsis</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>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)</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3>polymorphic_downcast example</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>#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);
|
|
||||||
...</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3><a name="numeric_cast">numeric_cast</a></h3>
|
|
||||||
<p>A <b>static_cast</b>, <b>implicit_cast</b> or implicit conversion will not
|
|
||||||
detect failure to preserve range for numeric casts. The <b>numeric_cast</b>
|
|
||||||
template function are similar to <b>static_cast</b> 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.</p>
|
|
||||||
<p>The requirements on the argument and result types are:</p>
|
|
||||||
<blockquote>
|
|
||||||
<ul>
|
|
||||||
<li>Both argument and result types are CopyConstructible [20.1.3].</li>
|
|
||||||
<li>Both argument and result types are Numeric, defined by <code>std::numeric_limits<>::is_specialized</code>
|
|
||||||
being true.</li>
|
|
||||||
<li>The argument can be converted to the result type using <b>static_cast</b>.</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
<h3>numeric_cast synopsis</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>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)</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3>numeric_cast example</h3>
|
|
||||||
<blockquote>
|
|
||||||
<pre>#include <boost/cast.hpp>
|
|
||||||
using namespace boost::cast;
|
|
||||||
|
|
||||||
void ariane(double vx)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
unsigned short dx = numeric_cast<unsigned short>(vx);
|
|
||||||
...
|
|
||||||
}</pre>
|
|
||||||
</blockquote>
|
|
||||||
<h3>numeric_cast rationale</h3>
|
|
||||||
<p>The form of the throws condition is specified so that != is not a required
|
|
||||||
operation.</p>
|
|
||||||
<hr>
|
|
||||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %B, %Y" startspan
|
|
||||||
-->28 June, 2000<!--webbot bot="Timestamp" endspan i-checksum="19846"
|
|
||||||
--></p>
|
|
||||||
<p>© 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.</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
153
cast_test.cpp
153
cast_test.cpp
@ -1,153 +0,0 @@
|
|||||||
// 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 <iostream>
|
|
||||||
#include <climits>
|
|
||||||
#include <limits>
|
|
||||||
#include <boost/cast.hpp>
|
|
||||||
|
|
||||||
# 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<Derived*>( base ); // downcast
|
|
||||||
assert( derived->kind() == 'D' );
|
|
||||||
|
|
||||||
derived = 0;
|
|
||||||
derived = polymorphic_cast<Derived*>( base ); // downcast, throw on error
|
|
||||||
assert( derived->kind() == 'D' );
|
|
||||||
|
|
||||||
base2 = polymorphic_cast<Base2*>( 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<Derived*>( base ); } // #1 assert failure
|
|
||||||
|
|
||||||
bool caught_exception = false;
|
|
||||||
try { derived = polymorphic_cast<Derived*>( 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<long>::max();
|
|
||||||
long large_negative_value = std::numeric_limits<long>::min();
|
|
||||||
signed char c = 0;
|
|
||||||
|
|
||||||
c = large_value; // see if compiler generates warning
|
|
||||||
|
|
||||||
c = numeric_cast<signed char>( small_value );
|
|
||||||
assert( c == 1 );
|
|
||||||
c = 0;
|
|
||||||
c = numeric_cast<signed char>( small_value );
|
|
||||||
assert( c == 1 );
|
|
||||||
c = 0;
|
|
||||||
c = numeric_cast<signed char>( small_negative_value );
|
|
||||||
assert( c == -1 );
|
|
||||||
|
|
||||||
// These tests courtesy of Joe R NWP Swatosh<joe.r.swatosh@usace.army.mil>
|
|
||||||
assert( 0.0f == numeric_cast<float>( 0.0 ) );
|
|
||||||
assert( 0.0 == numeric_cast<double>( 0.0 ) );
|
|
||||||
|
|
||||||
// tests which should result in errors being detected
|
|
||||||
|
|
||||||
caught_exception = false;
|
|
||||||
try { c = numeric_cast<signed char>( 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<signed char>( 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<unsigned long>( 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<unsigned long>( 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<int>( std::numeric_limits<double>::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
|
|
Loading…
x
Reference in New Issue
Block a user