Is decltype allowed for std :: declval <T> (the function itself, not the result of calling it)?

The following code runs a static statement in libstdc ++:

#include <utility> using t = decltype(std::declval<const void>); 

Should he?




Motivation for this question:

The following declval implementation proposed by Eric Nibler (which seems to be compile-time optimization)

 template<typename _Tp, typename _Up = _Tp&&> _Up __declval(int); template<typename _Tp> _Tp __declval(long); template<typename _Tp> auto declval() noexcept -> decltype(__declval<_Tp>(0)); 

it will be doubtful if the user can legally observe the type std::declval<const void> . Signature in standard

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

leads to the type const void () (or const void () noexcept in C ++ 17), while the proposed version leads to the type void () (or void () noexcept ).

+11
c ++ language-lawyer c ++ 11
May 19 '16 at 1:49
source share
1 answer

[declval] indicates that:

If this function is used by odr (3.2), the program is poorly formed.

This is basically it. In case of using odr-use functions from [basic.def.odr]:

A function whose name is displayed as a potentially evaluated expression is used as odr if it is a unique search result or a selected element of a set of overloaded functions (3.4, 13.3, 13.4), if it is not a pure virtual function, and either its name is clearly not qualified, or the form expressions pointer to an element (5.3.1).

But also:

An expression is potentially evaluated if it is not an unvalued operand (paragraph 5) or its subexpression.

And [dcl.type.simple]:

The decltype specifier operand is an unvalued operand (clause 5).

So, in decltype(std::declval<const void>) , std::declval not evaluated potentially and therefore odr is not used. Since one criterion on declval for a program will be poorly formed, and we will not meet it, I think that libstdC ++ erroneously emits a static statement.




Although I do not think this is a libstC ++ thing. I think this is more a question of when static_assert . Implementation of libstdc ++ declval :

 template<typename _Tp> struct __declval_protector { static const bool __stop = false; static typename add_rvalue_reference<_Tp>::type __delegate(); }; template<typename _Tp> inline typename add_rvalue_reference<_Tp>::type declval() noexcept { static_assert(__declval_protector<_Tp>::__stop, "declval() must not be used!"); return __declval_protector<_Tp>::__delegate(); } 

Both gcc and clang run static_assert in this context (but obviously not with decltype(std::declval<const void>()) , although in both cases we are in an invaluable context. Standard, what is the correct behavior to static_assert s.

+5
May 19 '16 at 2:33
source share
β€” -



All Articles