Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `decltype(static_cast<T>(...))` not always `T`?

For the following code, all but the last assertion passes:

template<typename T>
constexpr void assert_static_cast_identity() {
    using T_cast = decltype(static_cast<T>(std::declval<T>()));
    static_assert(std::is_same_v<T_cast, T>);
}

int main() {
    assert_static_cast_identity<int>();
    assert_static_cast_identity<int&>();
    assert_static_cast_identity<int&&>();
    // assert_static_cast_identity<int(int)>(); // illegal cast
    assert_static_cast_identity<int (&)(int)>();
    assert_static_cast_identity<int (&&)(int)>(); // static assert fails
}

Why is this last assertion failing, and static_cast<T> not always returning a T?

like image 778
Eric Avatar asked Oct 05 '19 21:10

Eric


People also ask

What is the point of static_cast?

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.

Can static_cast fail?

static_cast can't throw exception since static_cast is not runtime cast, if some cannot be casted, code will not compiles. But if it compiles and cast is bad - result is undefined.

Does static_cast take time?

static_cast MAY take time at run-time. For example, if you convert int to float then work is required. Usually casting pointers does not require any run-time cost.

How is static_cast implemented?

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.


1 Answers

This is hard-coded in the definition of static_cast:

[expr.static.cast] (emphasis mine)

1 The result of the expression static_­cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue. The static_­cast operator shall not cast away constness.

decltype respects the value category of its operand, and produces an lvalue reference for lvalue expressions.

The reasoning may be due to function names themselves always being lvalues, and so an rvalue of a function type cannot appear "in the wild". As such, casting to that type probably makes little sense.

like image 134
StoryTeller - Unslander Monica Avatar answered Oct 17 '22 10:10

StoryTeller - Unslander Monica