#include <iostream>
int main(){
using type = int[2];
static_cast<type>(type{1,2}); //#1
}
Clang and GCC both complain that #1
is ill-formed, and give weird diagnoses.
Clang reports
static_cast from 'int *' to 'type' (aka 'int [2]') is not allowed
GCC reports
invalid 'static_cast' from type 'type' {aka 'int [2]'} to type 'type' {aka 'int [2]'}
However, as per expr.static.cast#4
An expression E can be explicitly converted to a type T if there is an implicit conversion sequence ([over.best.ics]) from E to T
Isn't that converts a type to the same type be called identity conversion?
over.best.ics#general-8
If no conversions are required to match an argument to a parameter type, the implicit conversion sequence is the standard conversion sequence consisting of the identity conversion ([over.ics.scs]).
I think a crucial rule here is
The sequence of conversions is an implicit conversion as defined in [conv], which means it is governed by the rules for initialization of an object or reference by a single expression ([dcl.init], [dcl.init.ref]).
That means, assume a result object would be t
which will be initialized by the prvalue.
type t = type{1,2}; // #2
#2
is also rejected by Clang and GCC. However, such a case should be caught by dcl.init.general#15.9
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. A standard conversion sequence ([conv]) will be used, if necessary, to convert the initializer expression to the cv-unqualified version of the destination type; no user-defined conversions are considered. If the conversion cannot be done, the initialization is ill-formed. When initializing a bit-field with a value that it cannot represent, the resulting value of the bit-field is implementation-defined.
According to basic.lval#1.2
A prvalue is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv void.
In which case, Isn't that a prvalue of type type
cannot initialize the result object?
Clang assumes that array-to-pointer conversion applies to the operand. However, such a conversion is only permitted if the bullet steps into expr.static.cast#8. In other words, the conversion should not apply here for the operand in bullet 4.
GCC gives a more nonreasonable diagnosis. I wonder why the explicit conversion is forbidden by Clang and GCC?
If static_cast fails you will get a compile error and the program executable will never even be built. Your example has undefined behavior, not a failure or an error.
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.
static_cast is always resolved using compile-time type info. (This may involve a runtime action). If it's not an appropriate cast you either get a compile error or undefined behaviour. In your snippet it is OK because b is a D ; however if b were new B() then the cast compiles but causes undefined behaviour if run.
One effective way to convert a string object into a numeral int is to use the stoi() function. This method is commonly used for newer versions of C++, with is being introduced with C++11. It takes as input a string value and returns as output the integer version of it.
Raw arrays are difficult to keep in array form - in prvalue context an array decays to a pointer.
But does it apply static_cast
context also? The rules are outlined in [expr.static.cast]...
We're not casting to a reference, so we skip the first 3 clauses and arrive at [expr.static.cast]/4:
An expression
E
can be explicitly converted to a typeT
if there is an implicit conversion sequence ([over.best.ics]) fromE
toT
...
This won't work because ([conv.general]/3):
An expression
E
can be implicitly converted to a typeT
if and only if the declarationT t=E;
is well-formed, for some invented temporary variablet
And int t[2] = int[2]{1, 2};
isn't well-formed. The only legal way to initialize an array is specified in [dcl.init.general]/15.5:
... if the destination type is an array, the object is initialized as follows. Let x1, …, xk be the elements of the expression-list. ... the ith array element is copy-initialized with xi for each 1 ≤ i ≤ k.
There is no provision for "unwrapping" int[2]{1, 2}
into an expression-list here.
Otherwise, the result object is direct-initialized from
E
.
Similarly this won't work for the same reason that int x[2](int[2]{1, 2});
isn't well-formed.
Note that there is a special provision with regard to arrays in aggregates, which allows for easy copying (e.g. std::array
). There is no such treatment in raw arrays.
We skip over 5. 6, 7 don't apply. Which brings us to [expr.static.cast]/8:
The lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) conversions are applied to the operand.
. . .
So that's it, the cast is invalid. Both Clang and GCC seem to be correct. The error reporting differs slightly because Clang reports the decayed type, and GCC reports the original type.
As a workaround, cast to a reference type: static_cast<type&&>(type{1,2});
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With