2

In Boost ODEINT library, you can find a lot of static_cast keyword such as:

template<
class State ,
class Value = double ,
class Deriv = State ,
class Time = Value ,
class Algebra = typename algebra_dispatcher< State >::algebra_type ,
class Operations = typename operations_dispatcher< State >::operations_type ,
class Resizer = initially_resizer
>
class runge_kutta_dopri5: ....
{
    ...
    typedef typename stepper_base_type::value_type value_type;
    ...
    template< class System , class StateIn , class DerivIn , class StateOut , class DerivOut >
    void do_step_impl( System system , const StateIn &in , const DerivIn &dxdt_in , time_type t ,
        StateOut &out , DerivOut &dxdt_out , time_type dt )
    {
        const value_type a2 = static_cast<value_type> ( 1 ) / static_cast<value_type>( 5 );
        const value_type a3 = static_cast<value_type> ( 3 ) / static_cast<value_type> ( 10 );
        const value_type a4 = static_cast<value_type> ( 4 ) / static_cast<value_type> ( 5 );
        const value_type a5 = static_cast<value_type> ( 8 )/static_cast<value_type> ( 9 );
        .... 

Where value_type is determined by template.

My question is that if value_type is a simple type like double, is there any difference between static_cast<value_type> ( 5 ) and (double)5 ? I wonder why they have used such casting. Is it the same if value_type is double& or double&&?

torbani
  • 85
  • 5

1 Answers1

3

There is no difference.

They choose C++ style casts because they're MUCH safer.

C-style casts can perform any reinterpretation cast, which might not even remotely do what's expected, and this is especially dangerous when it happens silently deep in the bowels of a highly geneirc library like Boost ODEINT

Simple example:

struct FixedPoint { 
    int x; 
    FixedPoint(int x):x(x) {}
    operator double() const { return x/10.0; }
};

// deep in the bowels of a library, this happens:
double test = static_cast<double>(FixedPoint(42)); // ok 4.2

But, somewhere else, in some less fortunate's codebase:

struct FixedPoint { 
    int x; 
    FixedPoint(int x):x(x) {}
    double as_double() const { return x/10.0; }
};

// oops, good thing the compile catches this!
double test = static_cast<double>(FixedPoint(42)); // COMPILE ERROR

Imagine the carnage if that had been written

double test = (double) (FixedPoint(42)); // silent reinterpret_cast<double>

In short, in C++, never write the C-style cast. It's not useful.

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Depends. I gave a sample where it would be fine, and the second where you get Undefined Behaviour (and certainly not the results you expected) – sehe Feb 10 '15 at 20:28
  • Therefore, you mean `(double) (FixedPoint(42))` has no casting operator, so it is interpreted as sequences of its bits to fit in `double` type? – torbani Feb 10 '15 at 20:31
  • It's called "user-defined (implicit) conversion operator", but yes. "reinterpret_cast" ends up interpreting the bits of the FixedPoint object as a double instead. This is the nature of reinterpret_cast and you get it "for free" in C-style casts. Don't use that :) – sehe Feb 10 '15 at 20:33
  • Thank you very much. In this case, do `static_cast` and `static_cast` have the same meaning as `static_cast` too? – torbani Feb 10 '15 at 20:35
  • Yes, except they mandate that the result of the conversion is an lvalue reference (so it can be written to/taken the address of) or an rvalue reference (so that it can be read/written/moved from; the latter is hypothetical for doubles) – sehe Feb 10 '15 at 20:38