user3502661
user3502661

Reputation: 133

Function-style casts considered harmful?

I understand that generally C-style casts are considered harmful. So, given a class Widget

class Widget{
public:
  explicit Widget(Gizmo gizmo);
};

I could call a function like this:

functionThatTakesAWidget((Widget) gizmo);

using a C-style cast. Or I could write it using a function-style cast:

functionThatTakesAWidget(Widget(gizmo));

but this is exactly equivalent. So no better or worse. And If I really wanted to avoid a C-style cast I could write:

functionThatTakesAWidget(static_cast<Widget>(gizmo));

But given a class Doohickey:

class Doohickey {
public:
  Doohickey(Gizmo left_gizmo, Gizmo right_gizmo);
};

I can't avoid writing:

functionThatTakesADoohickey(Doohickey(left_gizmo, right_gizmo));

I assume this is not considered a 'cast' at all? But what is the difference between this and a function-style cast? Why is this OK but a function-style cast is not?

Upvotes: 3

Views: 862

Answers (3)

user48956
user48956

Reputation: 15788

I believe:

C c;
(A)c

calls the casting operator "C::operator A ()". Which may be called when a C is provided, but an A is required. For example:

void f(A const&) { ... }
f(c);

Also,

A(c)

calls the constructor: "A::A(const& C)".

I believe that if you don't define the cast operator, C++ may end calling the constructor implicitly to get the A. Sometimes this is a big disaster (let's say this constructor formats your hard drive and files for a divorce). So there's two remedies:

class A {
public:
   explicit A(const& C);  // Don't call this when asking to cast to an A.
}

and also

static_cast<A>(C);  // Really, just call the casting operator, don't implicitly cast.

Because "function-style" casts may file for divorce (by calling the constructor), they're considered harmful.

There's nothing wrong with:

f(c1,c1)

to get a A. People typically wouldn't think of it as a 'cast' which usually means 'turn this type of object into that type'.

Typically you wouldn't write:

void A A(const& C) {...} // function

to get

d = A(c)

because its confusing. (is A class or a function?)

And you'd prefer not to write:

void A toA(const& C) {...}

simply because this functionality is better off encapsulated in the A class. But its not otherwise particularly harmful.

Upvotes: 0

Deduplicator
Deduplicator

Reputation: 45654

The reasons for avoiding C-Style casts are:

  • Being explicit about what kind of casting happens, thus making sure no other type actually does.
  • Making casts easier findable.

While the function-style cast looks safer, it's actually a C-style cast in disguise, so it does not really add anything.

The driving reason behind being explicit is letting the compiler assert your assumptions, instead of silently doing (sometimes) the wrong thing.
IMHO, some purists go to far in their zeal though.

Upvotes: 1

M.M
M.M

Reputation: 141544

I wouldn't call Widget(gizmo) a "C-style cast". In C you can't cast to a struct type anyway. The main problem with "C-style casts" is when a pointer or reference cast is happening. Then the C-style cast can be ambiguous or cause undefined behaviour.

A value conversion is a different concept to a reference cast, in my view, and you don't need to use the same conventions for both.

The code is creating a temporary Widget, passing gizmo to the constructor. I think the static_cast version is misleading, and the Widget(gizmo) is fine.

BTW you could make functionThatTakesADoohickey overloaded to take a Gizmo, or a std::initializer_list<Gizmo>.

Upvotes: 0

Related Questions