What Exactly Is or Was the Purpose of C++ Function-Style Casts

What exactly is or was the purpose of C++ function-style casts?

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

Function-style cast vs. constructor

Syntactically, it is always a cast. That cast may happen to call a constructor:

char s [] = "Hello";
// Function-style cast; internally calls std::basic_string<char>::basic_string(char const*, Allocator)
std::string s2 = std::string(s);
// C-style cast; internally calls std::basic_string<char>::basic_string(char const*, Allocator)
std::string s3 = (std::string) s;

Is a C-style cast identical to a function-style cast?

I don't have a quote from the standard, but cppreference is usually good enough.

Explicit type conversion

The functional cast expression consists of a simple type specifier or a typedef specifier (in other words, a single-word type name: unsigned int(expression) or int*(expression) are not valid), followed by a single expression in parentheses. This cast expression is exactly equivalent to the corresponding C-style cast expression.

As for Resharper, it's possible that to it C++ cast includes a functional cast, as that is only valid in C++.

The answer you linked in your question explains how safe a functional cast is. In your case int(d) should be equivalent to static_cast<int>(d). But in general a C-style or functional cast are unsafe as they can be equivalent to reinterpret_cast in certain situations, e.g. (double*)some_int_ptr.

Function style casting vs calling constructor

It's a functional-style type conversion which creates a t from an int by calling the constructor. There is no way to explicitly call a constructor in C++.

This is described in [expr.type.conv] (N3337):

5.2.3 Explicit type conversion (functional notation)

1) A simple-type-specifer (7.1.6.2) or typename-specifer (14.6) followed by a parenthesized expression-list
constructs a value of the specified type given the expression list. If the expression list is a single expression,
the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding
cast expression (5.4). If the type specified is a class type, the class type shall be complete. If the expression
list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5, 12.1),
and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.

Since t is a simple-type-specifier, this is equivalent to the corresponding cast expression. This is allowed to carry out the equivalent of a static_cast ([expr.cast]/4), which defines the final result of the conversion:

[expr.static.cast]/4: Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The
effect of such an explicit conversion is the same as performing the declaration and initialization and then
using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and
only if the initialization uses it as a glvalue.

Why does C style cast allow you to convert to a private base class?

It's because in C it was allowed to convert any pointer to any other pointer using this cast and C++ tries to be C-compatible as much as possible, but tries to do a good job to be correct when it comes to classes, so C style cast is stronger than reinterpret_cast in this situation.

What is the difference between static_cast and C style casting?

C++ style casts are checked by the compiler. C style casts aren't and can fail at runtime.

Also, c++ style casts can be searched for easily, whereas it's really hard to search for c style casts.

Another big benefit is that the 4 different C++ style casts express the intent of the programmer more clearly.

When writing C++ I'd pretty much always use the C++ ones over the the C style.

c++ difference between reinterpret cast and c style cast

reinterpret_cast and const_cast are ways of getting around the C++ type system. As you noted for reinterpret_cast, this usually translates to little or no assembly code.

static_cast mostly respects the C++ type system. It could convert a number from one type to another, or call a constructor, or call a conversion function. Or for a derived-to-base conversion, it might involve adding byte offsets and/or lookups into a vtable. static_cast can also bend the type system's rules by "downcasting" a pointer or reference from a non-virtual base type to a derived type, possibly subtracting a byte offset.

And then there are pointers-to-member. They're probably beside the point here, but static_cast does things to them more or less analogous to class pointer conversions.

dynamic_cast respects the C++ type system even more strictly. In its useful form, it checks at runtime whether or not a pointer/reference actually points/refers to an object of the specified type. It typically calls a magic library function under the covers.

A function-style cast with one argument has exactly the same effect as a C-style cast. (With more than one argument, a function-style cast must be a temporary initialization using a class constructor.) A C-style cast does the first thing that makes sense out of the following list:

  • a const_cast
  • a static_cast
  • a static_cast and then a const_cast
  • a reinterpret_cast, or
  • a reinterpret_cast and then a const_cast

One exception: C-style casts can ignore private and protected inheritance relations between classes, pretending they have a public inheritance relation instead.

C-style casts are usually not preferred in C++ because it's less specific about what you want to happen.



Related Topics



Leave a reply



Submit