tags:

views:

538

answers:

9

C++ comes with four built-in casts.

  1. static_cast
  2. dynamic_cast
  3. const_cast
  4. reinterpret_cast

Not to meantion the frowned upon C (style*)cast.

Additionally boost supplies a lexical_cast, are there any other useful casts that you use or would like to exist?

+6  A: 

It's worth remembering that constructors can also be considered to act as casts, and will be used by the compiler to perform cast-like conversions. For example:

class Person {
   public:
      Person( const std::string & name );
   ...
};

The Person constructor acts a conversion from string -> Person:

Person p = Person( "fred" );

and will be used by the compiler when a string needs to conversted to a person:

void PrintPerson( const Person & p ) {
   ...
}

the compiler can now convert a string to a Person:

string name = "fred";
PrintPerson( name );

but note that it cannot do this:

PrintPerson( "fred" );

as this would require the compiler to construct a chain of conversions.

Edit: I have posted a follow-up question on the topic of conversions - see http://stackoverflow.com/questions/867462/c-implicit-conversions.

anon
did you mean to write Person p = "fred"?
Idan K
No, I didn't - I think you'll find that won't work.
anon
it does on VS2008, no reason it shouldn't
Idan K
If you want it to not work you need the explicit keyword on your ctor. This is plain old C++.
Logan Capaldo
There is no conversion from a char * to a Person.
anon
+8  A: 

There's also the function-style cast which looks like a function or constructor call. This resolves to the constructor call for classes, and (more generally) to C-style casts for all other types.

Examples:

int x = int(1.0);       // equals `(int)1.0`
string s = string("x"); // equals call to constructor

The call to a constructor can also be achived using an explicit cast (apart from the C-style cast which would also work):

string s = static_cast<string>("x"); // is the same as above!
Konrad Rudolph
is this use of static_cast useful in some contexts?
Idan K
@daniel: there are some C++ folks who say only to use the `static_cast` and *never* the function-style constructor cast for reasons of disambiguation. I'm not sure that I always agree since constructor call syntax is just more handy.
Konrad Rudolph
I see, well I'll have to agree with you, thanks!
Idan K
This way of casts is more natural and understandable.
Mykola Golubyev
I'm in the "don't use c-style casts" boat. For one this, static_cast is explicit. A function style cast will remove a const qualifier, perhaps inadvertently. This can introduce nightmarish bugs. You don't have this issue with static_cast. C++ is a language where it pays to be explicit.
Jeffrey Martinez
@Jeffrey Martinez: OTOH, `static_cast<unsigned>(0)` gives the reader exactly nothing compared to `unsigned(0)`. IMO.
just somebody
@just: well, use the appropriate literal: `0U` . And for non-literals, the `static_cast` solution should definitely be preferred. The problem with your cast (when used on non-literals) is precisely that it hides potential bugs because it can decay to a `reinterpret_cast` when needed.
Konrad Rudolph
@Konrad Rudolph: I find the suffixes ugly and dangerous (but that's because I find terribly significant but hard to spot stuff hiding at the far end of a symbol dangerous in general; `0U` is short and the modifier is hard to miss, but the situation quickly changes as the number grows, and I go for consistency). Also, I'm well aware of dangers of "function call" casts and would only advocate their use with literals, sorry I wasn't more explicit about that.
just somebody
+3  A: 

There is also a horrid union_cast.

It's bad because strictly speaking it is UB, but if you know what you are doing, it can be useful for converting pointers to member functions to void* and back, not all compilers allow to do this with reinterpret_cast.

But still it's better avoided..

Alex Jenter
Pointers to member functions are often larger than void * - casting them anyway will lose data, which will obviously cause problems...
bdonlan
+4  A: 

You might want to use the boost pointer casts (boost::static_pointer_cast,...) if you use shared_ptr. They can also be used for standard pointers.

stefaanv
+2  A: 

One really useful boost cast is operator (function really) is numeric_cast(number);

This checks that the number you are casting is in range for the destination type.

eg

long long big_number = ....

int num = numeric_cast<int>(big_number);  // throws an exception is big_number is too big

http://www.boost.org/doc/libs/1_39_0/libs/numeric/conversion/doc/html/boost_numericconversion/improved_numeric_cast__.html

iain
+5  A: 

My favorite and most loved cast is implicit_cast. It only succeeds if the types can be implicitly converted.

Useful for conversion from some type into void* or from some derived class into a base (if you want to select a specific instance of an overloaded function or constructor) or to safely add const-qualifications and any other scenario where you really just need implicit conversions to happen and even static_cast is too powerful.

Also read How does C++ pick which overload to call.

boost/implicit_cast.hpp. You can add this to your code collection too, if you want

template<typename T> struct identity { typedef T type; };
template<typename Dst> Dst implicit_cast(typename identity<Dst>::type t)
{ return t; }
Johannes Schaub - litb
Cool, I thought of writing an up_cast with exactly the same semantics only I wouldn't have used identity<T>, what function does it fill? Why not just use template<class T, class U> T implicit_cast(U u) { return u; }
Motti
Johannes Schaub - litb
+2  A: 

ACE has a truncate_cast. It is mostly useful for optimizing code like the following:

foo_t bar = ...;
short baz;

if (bar > SHORT_MAX)
  baz = SHORT_MAX;
else
  baz = static_cast<short> (bar);

This could be replaced by:

foo_t bar = ...;
short baz = ACE_Utils::truncate_cast<short> (bar);

Depending on the underlying type of foo_t, truncate_cast will optimize away the if() statement entirely, and also address compiler diagnostics resulting from comparison of signed and unsigned types. The choice of which way to go is performed at compile-time through a template metaprogram.

Ideally one should not need such a cast/truncation if compatible types are used correctly but sometimes there's no getting around incompatible types when working with legacy interfaces, particularly with low level OS calls.

Note that it's easy to abuse such a cast, which is why the authors explictly state it is meant for internal use, and that the cast shouldn't be used to work around compiler diagnostics.

Void
A: 

Visual Studio 6 allowed rvalues to bind to regular references (not to be mistaken with C++0x's rvalue references). When porting to Visual Studio 2003 all the places that our code depended on this non-standard behaviour had to be changed.

E.g. Definition

bool get_string(char* buff, int& length)
{
    if (myStrLength >= length)
    {
        length = myStrLength;
        return false; // Nobody used exceptions in 1998 :o)
    }
    strcpy(buff, myStr);
    return true;
}

Usage:

char buff[1024]; 
get_string(buff, sizeof(buff)); // Assumes size is sufficient

In order to make the port much faster we wrote the following lvalue_cast.

// Danger, only use this on function arguments that will not be stored
template <class T>
T& lvalue_cast(const T& t)
{
    return const_cast<T&>(t);
}

Since the temporary is in scope till the next sequence point (the next semi-colon) and rvalues aren't true consts this is well defined (to my understanding at least).

Motti
+1  A: 

There are counterparts of C++ casting operators defined in Boost.Lambda which are very useful in various lambda expressions from simple ones:

vector<int> v1; // signed indices
v1.push_back(0);
v1.push_back(1);
v1.push_back(2);

vector<size_t> v2(v1.size()); // unsigned +1 incides 
std::transform(v1.begin(), v1.end(), v2.begin(),
(boost::lambda::ll_static_cast<size_t>(boost::lambda::_1) + 1));

to much more complex using ll_dynamic_cast operator, for instance, to filter objects of particular (derived) type in a sequence:

mloskot