#include <utility> using t = decltype(std::declval<const void>);
应该是?
这个问题的动机:
以下声明实现proposed by Eric Niebler(显然是编译时优化)
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));
如果用户可以合法地观察std :: declval< const void>的类型,将是有问题的.标准中的签名
template <class T> add_rvalue_reference_t<T> declval() noexcept;
在C 17中导致类型为const void()(或const void()noexcept),而提出的版本导致类型为void()(或void()noexcept).
解决方法
If this function is odr-used (3.2),the program is ill-formed.
基本上是这样在功能方面,odr-use意味着,从[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).
但也:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression
thereof.
和[dcl.type.simple]:
The operand of the
decltype
specifier is an unevaluated operand (Clause 5).
所以在decltype(std :: declval< const void>)中,std :: declval不是潜在的评估,因此不会被odr使用.既然这是一个程序声明的标准,我们不满足,我觉得libstdc是错误的发出静态断言.
虽然我不认为这是一个libstc的事情.我认为这更是一个static_asserts被触发的问题.声明的libstdc实现是:
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(); }
在这种情况下,gcc和clang都会触发static_assert(但是显然不会使用decltype(std :: declval< const void>()),即使在这两种情况下我们处于一个未被评估的上下文中,我怀疑这是一个错误,但是可能在标准中可能不太明确指出触发static_asserts的正确行为.