38

I am talking about "type(value)"-style casts. The books I have read pass over them quickly, saying only that they are semantically equivalent to C-style casts, "(type) value", and that they should be avoided. If they mean the same thing an old-style cast does, why were they ever added to the language? Also, because declarations can contain superfluous parentheses, this code: "T x(T(y));" doesn't do what someone intending to use the function-style casts would expect; it declares a function named x accepting a T and returning a T rather than constructing a T variable named x by casting y to a T.

Were they a mistake in the design of the language?

Cplusplusstudent
  • 383
  • 1
  • 3
  • 4

6 Answers6

35

Function style casts bring consistency to primitive and user defined types. This is very useful when defining templates. For example, take this very silly example:

template<typename T, typename U>
T silly_cast(U const &u) {
  return T(u);
}

My silly_cast function will work for primitive types, because it's a function-style cast. It will also work for user defined types, so long as class T has a single argument constructor that takes a U or U const &.

template<typename T, typename U>
T silly_cast(U const &u) {
    return T(u);
}

class Foo {};
class Bar {
public:
    Bar(Foo const&) {};
};

int main() {
    long lg = 1L;
    Foo f;
    int v = silly_cast<int>(lg);
    Bar b = silly_cast<Bar>(f);
}
leedm777
  • 23,444
  • 10
  • 58
  • 87
  • 6
    This seems the opposite of helpful in templates. I would be extra careful to *avoid* C-style and function-style casts in generic programming, since e.g. your `silly_cast` can do anything a C-style cast can, and it's not clear whether that's intentional. – aschepler Dec 17 '10 at 22:02
  • 2
    In your example, `Foo` can be implicitly cast to `Bar`. And since `long` can also be implicitly cast to `int`, no cast at all is required. On the other hand, if you declare the constructor explicit, a cast is required, but `static_cast` works as well, with a much cleaner syntax. – Philipp Dec 17 '10 at 22:27
  • 5
    Your example don't seem to show a reason for `T(x)`. You can write your template to `return (T)u;` and it is exactly equivalent. – Johannes Schaub - litb Dec 17 '10 at 23:25
  • 3
    Like I said, it's a silly example. The point is demonstrating the uniform notation :-) – leedm777 Dec 20 '10 at 17:50
18

The purpose of them is so you could pass more than one argument to a class' constructor:

T(a1, a2); // call 2-argument constructor
(T)(a1, a2); // would only pass a2.

There is no mechanism that the (T) expr style cast would be able to pass multiple arguments, so a new form of conversion was needed. It's natural to define (T) expr as a degenerate case of T(expr).

Contrary to what some people here say, (T) expr works exactly like T(expr), so it will work just fine with class types too.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
13

It is somewhat easier to parse the function-style casts in a language where parentheses are already heavily (over-)used.

Were they a mistake? Possibly - but only to the extent that they were unable to completely supersede the C-style casts, and therefore provided a Perl-like "there's more than one way to do it" mechanism for casting. With the explicit and distinctive modern casts:

dynamic_cast<type>(value);
reinterpret_cast<type>(value);
static_cast<type>(value);
const_cast<type>(value);

there is no reason to use the C-style casts any more, and less reason to use function-style casts.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 11
    I actually like the verboseness of C++style casts. It helps discourage excessive casting, and it makes casts stick out like a sore thumb. – Fred Larson Dec 17 '10 at 21:49
1

C-style casts should not be used.

Function-style casts should be used, especially when the target type is a class name (or class template specialization). They fit the pattern of apparent constructor calls in the case with one argument.

MyClass( expr );   // Creates temporary, initialized like MyClass obj( expr );
MyClass( e1, e2 ); // Similar, and no other way to write this.
int( expr );       // Function-style cast.
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • i assume you mean for built-in arithmetic types. for pointers and references, really a better idea to use the named casts. a c-style cast, whether expressed as `(T)x` or as `T(x)`, can do things you'd not expect, and it's difficult to see what exactly it does – Cheers and hth. - Alf Dec 17 '10 at 21:58
1

AFAIK function-style casts are an extension to native types of the usual syntax of temporary creation for classes: as long as you can create a temporary object inside an expression using the syntax ClassName(parameters), there's no reason why you shouldn't do that with native types. edit Notice that, as @steve said, this is very useful in templates

Notice that one-parameter constructors in C++ are often somehow "felt" as conversion facilities, see for example the syntax (conversion constructor) that allows you to initialize a new object using an equal sign followed by a value

ClassName MyObject = 3;

which actually means

ClassName MyObject(3);

and (presumably) calls the one-int-parameter constructor of ClassName.

By the way, here's a nice page about function-style casts.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
0

What book was this??? It's the C-style casts which are generally thought to be a bad idea. Most modern C++ code looks like this (when a cast is needed)

x = sometype( y );

rather than

x = (sometype) y;

Apart from anything else, the former syntax looks much more like a constructor call, which in most cases it probably is, though the two forms are actually semantically identical.

unquiet mind
  • 1,082
  • 6
  • 11
  • 1
    uhm, this is just notation. i.e. personal preference. i'd prefer the former, but have no problem with the latter. the real dividing line is between the c-style cast (regardless of notation) and the named casts. the named casts are more safe in that each does only one job and indicates the intention via name, and they can more easily be recognized – Cheers and hth. - Alf Dec 17 '10 at 22:00
  • @Alf True, but notation is important. But in reality it is almost never necessary to use either cast in well-written C++ code, as the compiler will do it for you. The only casts in my own code (except for some trivial ones to get correct formatting in I/O) are dynamic_casts. – unquiet mind Dec 17 '10 at 23:49
  • 1
    It goes to show how people's experiences are different when "Most modern C++ code" I've read uses `cpp_cast(operand)` nearly exclusively. Am I reading too little code or just _better_ code? (fwiw, the vast majority of the code I read is my own...) Either way, I'll be sticking to the clear intention-signalling C++ casts, so I don't have to guess what I meant. It'd be nice if others did the same! – underscore_d Dec 21 '15 at 23:33
  • 1
    Actually, there are good reasons to prefer `static_cast(operand)`. If you want to search for casts in your code base, try looking for pairs of parens :) Though sometimes it may be the right thing to do, casting is never a good thing and should have ugly syntax. – Timtro Aug 03 '17 at 19:17
  • 3
    As a point of reference, the C++ Core Guidelines has a section related to this: [ES.49: If you must use a cast, use a named cast](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es49-if-you-must-use-a-cast-use-a-named-cast). Note that at least at the time I linked this, this guideline also states "When converting between types with no information loss (e.g. from float to double or int64 from int32), brace initialization may be used instead". So it would seem `sometype(y)` is discouraged while `sometype{y}` is encouraged. – Louis Langholtz Feb 03 '18 at 03:55