14

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?

Motti
  • 110,860
  • 49
  • 189
  • 262

10 Answers10

10

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; }
Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    Cool, I thought of writing an up_cast with exactly the same semantics only I wouldn't have used identity, what function does it fill? Why not just use template T implicit_cast(U u) { return u; } – Motti May 15 '09 at 09:24
  • 5
    With the boost one's, you can cast to a reference: implicit_cast(t), while your's will deduce U, and will copy everything. If an conversion failure occurs, the compiler will point to the caller in the boost version. But in your case, the conversion happens within the function and the error message would probably not be as simple. identity makes it require an explicit parameter. otherwise, it would accept things like "implicit_cast(t)" – Johannes Schaub - litb May 15 '09 at 09:28
9

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
  • 530,221
  • 131
  • 937
  • 1,214
  • is this use of static_cast useful in some contexts? – Idan K May 14 '09 at 12:02
  • 3
    @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 May 14 '09 at 12:04
  • This way of casts is more natural and understandable. – Mykola Golubyev May 14 '09 at 12:11
  • 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 May 14 '09 at 16:15
  • @Jeffrey Martinez: OTOH, `static_cast(0)` gives the reader exactly nothing compared to `unsigned(0)`. IMO. – just somebody Feb 05 '10 at 23:15
  • @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 Feb 06 '10 at 13:33
  • @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 Feb 06 '10 at 14:07
7

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 C++ implicit conversions.

Community
  • 1
  • 1
4

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
  • 14,072
  • 2
  • 31
  • 53
4

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
  • 10,798
  • 3
  • 37
  • 41
3

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

Community
  • 1
  • 1
Alex Jenter
  • 4,324
  • 4
  • 36
  • 61
  • 1
    Pointers to member functions are often larger than void * - casting them anyway will lose data, which will obviously cause problems... – bdonlan May 14 '09 at 18:31
  • I indeed feel safer using [memcpy_cast](http://stackoverflow.com/a/17854181/688659) instead – gx_ Jul 25 '13 at 09:39
2

memcpy_cast is a strictly Standard-compliant thus safe and portable alternative to type punning:

#include <cstring>

template<typename To, typename From>
inline To memcpy_cast(From x)
{
    // Constraints on types from STLSoft's union_cast:
    //  (1) Sizes must be the same.
    //  (2) Both must be of POD type.
    //  (3) There must be either a change of const/volatile,
    //                        or a change of type, but not both.
    //  (4) Both must be non-pointers, or must point to POD types.
    // 
    // Here checking only (1):
    STATIC_ASSERT(sizeof (To) == sizeof (From));

    To ret;
    std::memcpy(&ret, &x, sizeof ret);
    return ret;
}

(where STATIC_ASSERT is some compile-time assertion macro (or C++11's static_assert), and the constraints come from STLSoft's union_cast.hpp).

You can then try things like

uint32_t u = 0x1234ABCD;
//float f = *(float*)&u; // unsafe
float f = memcpy_cast<float>(u); // safe

(Here's another implementation: dbg's memcpy_cast.hpp.)

(Edit: Also, Boost.SIMD has a bitwise_cast which internally uses a memcpy_cast.)

gx_
  • 4,690
  • 24
  • 31
2

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 - Othman
  • 3,441
  • 18
  • 18
1

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:

Community
  • 1
  • 1
mloskot
  • 37,086
  • 11
  • 109
  • 136
0

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
  • 110,860
  • 49
  • 189
  • 262