[declval] stipulates that:
If this function is odr-used (3.2), the program is ill-formed.
That's basically it. Where functions are concerned, odr-use means, from [basic.def.odr]:
A function whose name appears as a potentially-evaluated expression is odr-used
if it is the unique lookup result or the selected member of a set of overloaded functions (3.4, 13.3, 13.4),
unless it is a pure virtual function and either its name is not explicitly qualified or the expression forms
a pointer to member (5.3.1).
But also:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression
thereof.
And [dcl.type.simple]:
The operand of the decltype
specifier is an unevaluated operand (Clause 5).
So in decltype(std::declval<const void>)
, std::declval
isn't potentially evaluated and hence it's not odr-used. Since that's the one criteria on declval
for the program to be ill-formed and we don't meet it, I think libstdc++ is wrong to emit the static assertion.
Though I don't think this is a libstc++ thing. I think it's more of a question of when static_assert
s get triggered. The libstdc++ implementation of declval
is:
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 trigger that static_assert
in this context (but obviously not with decltype(std::declval<const void>())
, even though we're in an unevaluated context in both cases. I suspect that's a bug, but it may simply be underspecified in the standard what the correct behavior is with regards to triggering static_assert
s.