Tutorial :What other useful casts can be used in C++



Question:

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?


Solution:1

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; }  


Solution:2

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!  


Solution:3

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.


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


Solution:5

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


Solution:6

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


Solution:7

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.


Solution:8

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


Solution:9

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:


Solution:10

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


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »