Насколько я знаю, я не могу объявить ссылку rvalue на void
.
Например, следующий код плохо сформирован:
void f(void &&v) { }
Из [20.2.6/1] (function template declval) у нас есть объявление для declval
, которое:
template <class T>
add_rvalue_reference_t<T>
declval() noexcept;
Таким образом, declval<void>
(скажем так) приведет к void &&
, что я догадался, что он был плохо сформирован, как и в предыдущем примере.
В любом случае, следующий минимальный рабочий пример компилирует:
#include<utility>
int main() {
decltype(std::declval<void>())* ptr = nullptr;
}
Обратите внимание, что также верно следующее:
static_assert(std::is_same<decltype(std::declval<void>()), void>::value, "!");
Я бы предположил, что это будет void&&
, как упоминалось ранее (или, лучше, я ожидал, что он не скомпилируется).
На самом деле, это, оказывается, ссылка rvalue для любого другого не ссылочного типа.
В качестве примера:
static_assert(std::is_same<decltype(std::declval<int>()), int&&>::value, "!");
Является ли declval<void>
допустимым выражением или нет? Является ли код выше законным?
Почему поведение в случае void
отличается от любого другого типа? (Ибо он не работал бы иначе, может быть ответом, если код является законным).
Если это законно, то где это допускает стандарт? Я не смог найти дело.
Конечно, в стандарте говорится:
Параметр шаблона T declval может быть неполным.
В любом случае, это приведет к неприемлемому типу (void&&
), и он работает вокруг него, отбрасывая ссылку rvalue.