Почему `decltype (static_cast <T> (…))` не всегда `T`?

24

Для следующего кода проходят все, кроме последнего утверждения:

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
}

Почему это последнее утверждение не выполняется и static_cast<T>не всегда возвращает a T?

Эрик
источник
Я добавляю T_cast i{1};я invalid initialization of non-const reference of type 'T_cast' {aka 'int (&)(int)'} from an rvalue of type '<brace-enclosed initializer list>', так что для какой - то причине T_castэто , int (&)(int)а не int (&&)(int).
Кевин

Ответы:

21

Это жестко закодировано в определении static_cast:

[Expr.static.cast] (акцент мой)

1 Результат выражения static_­cast<T>(v)является результатом преобразования выражения vв тип T. Если Tэто ссылочный тип lvalue или rvalue ссылка на тип функции, результатом будет lvalue ; Если Tэто ссылка на тип объекта, то результатом является значение x; в противном случае результат является prvalue. static_­cast Оператор не отбросит константность.

decltype уважает категорию значения своего операнда и создает ссылку lvalue для выражений lvalue.

Причина может быть в том, что сами имена функций всегда являются lvalues, и поэтому rvalue типа функции не может появляться «в дикой природе». Таким образом, приведение к этому типу, вероятно, не имеет большого смысла.

Рассказчик - Unslander Monica
источник
этот вопрос более подробно рассматривает «rvalue [s] типа функции [not] появляются [ing]« в дикой природе »»
Эрик