Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is std::declval<void>() a valid expression?

As far as I know, I cannot declare an rvalue reference to void.
As an example, the following code is ill-formed:

 void f(void &&v) { }

From [20.2.6/1] (function template declval) we have a declaration for declval that is:

template <class T>
add_rvalue_reference_t<T>
declval() noexcept;

Thus, declval<void> (let me say) would result in void &&, that I guessed it was ill-formed as well as in the previous example.

Anyway, the following minimal, working example compiles:

#include<utility>

int main() {
    decltype(std::declval<void>())* ptr = nullptr;
}

Note that the following is true too:

static_assert(std::is_same<decltype(std::declval<void>()), void>::value, "!");

I would have expected it to be void&& as previously mentioned (or better, I was expecting it fails to compile).
Actually, it happens to be an rvalue reference for any other non-reference type.
As an example:

static_assert(std::is_same<decltype(std::declval<int>()), int&&>::value, "!");

Is declval<void> a valid expression or not? Is the code above legal?
Why does the behavior in case of void is different than with any other type? (For it wouldn't have worked otherwise could be an answer, if the code is legal).

If it's legal, where does the standard allow that? I've not been able to find the case.
Of course, the standard says:

The template parameter T of declval may be an incomplete type.

Anyway, here it would result in a non acceptable type (void&&) and it works around it discarding the rvalue reference.

like image 684
skypjack Avatar asked Sep 01 '16 21:09

skypjack


People also ask

What is std:: declval?

typename std::add_rvalue_reference<T>::type declval() noexcept; (since C++11) Converts any type T to a reference type, making it possible to use member functions in decltype expressions without the need to go through constructors.


1 Answers

add_rvalue_reference<T> only results in T&& if T is a referenceable type. So when T is void, the result is just void. This is also why you can add_rvalue_reference<int&&> and not get an error attempting to construct a reference to a reference. (Same with lvalue reference.)

like image 68
GManNickG Avatar answered Sep 19 '22 20:09

GManNickG