Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this value downcast (static_cast to object type) allowed in C++20?

To my surprise, gcc 11.2 accepts this code, but only in C++20 mode:

struct Base {};
struct Derived : Base { int i; };
int f(Base& b) { return static_cast<Derived>(b).i; }
//                                  ^~~~~~~ oops, forgot the `&`

Likewise, MSVC 19.29 accepts it in C++20 mode and rejects it in C++17 mode, but clang rejects it even in C++20 mode.

Looking at the assembler output, f always returns 0, so it's ignoring the actual data of any potential Derived passed to f.

Is this UB, or is it legal in C++20, and if so, why?

like image 421
ecatmur Avatar asked Aug 10 '21 07:08

ecatmur


People also ask

What does static_cast do in C?

static_cast is used to convert from pointer to base class to pointer to derived class, or between native types, such as enum to int or float to int. The user of static_cast must make sure that the conversion is safe. The C-style cast does not perform any check, either at compile or at run time.

Why do we use static_cast in C++?

In C++ the static_cast<>() will allow the compiler to check whether the pointer and the data are of same type or not. If not it will raise incorrect pointer assignment exception during compilation.

What does static_cast char do in C++?

static_cast in C++ The static_cast is used for the normal/ordinary type conversion. This is also the cast responsible for implicit type coercion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. This can cast related type classes.

How does static_cast int work?

The static_cast operator converts variable j to type float . This allows the compiler to generate a division with an answer of type float . All static_cast operators resolve at compile time and do not remove any const or volatile modifiers.

What is the use of static cast in C++?

This type of static_cast is used to implement move semantics in std::move. (since C++11) 4) If new_type is the type void (possibly cv-qualified), static_cast discards the value of expression after evaluating it.

Does static_cast check if member actually exists in the point-to object?

This static_cast makes no checks to ensure the member actually exists in the runtime type of the pointed-to object. 10) A prvalue of type pointer to void (possibly cv-qualified) can be converted to pointer to any object type.

When does static_cast perform an ill-formed downcast?

2) If new_type is a reference or pointer to some class D and expression is lvalue of its non-virtual base B or prvalue pointer to it, static_cast performs a downcast. (This downcast is ill-formed if B is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D .)

What is the use of implicit cast in C++?

This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int, char to int, etc. This can cast related type classes. If the types are not same it will generate some error.


1 Answers

It is legal in C++20.

[expr.static.cast]/4:

An expression E can be explicitly converted to a type T [...] if T is an aggregate type ([dcl.init.aggr]) having a first element x and there is an implicit conversion sequence from E to the type of x.

[dcl.init.aggr]/2:

The elements of an aggregate are: [...] for a class, the direct base classes in declaration order, followed by the direct non-static data members ([class.mem]) that are not members of an anonymous union, in declaration order.

So Derived is an aggregate whose first element is Base, and since C++20, it is permitted to create an aggregate from its first element.

This feature is introduced in P1975R0 "Fixing the wording of parenthesized aggregate-initialization".

like image 96
cpplearner Avatar answered Oct 19 '22 11:10

cpplearner