以下代码在libstdc++上触发静态断言:
#include <utility>
using t = decltype(std::declval<const void>);
应该是?
这个问题的动机:
以下
declval
实现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;
结果类型为
const void ()
(或C++ 17中的const void () noexcept
),而建议的版本结果为void ()
(或void () noexcept
)。 最佳答案
[declval]规定:
基本上就是这样。在涉及功能的地方,odr-use的意思是来自[basic.def.odr]:
但是也:
和[dcl.type.simple]:
因此,在decltype(std::declval<const void>)
中,std::declval
不会被评估,因此不会被使用。由于那是declval
上格式错误的一个标准,我们不满足,因此我认为libstdc++发出静态断言是错误的。
虽然我不认为这是libstc++的事情。我认为这更多是关于何时触发static_assert
的问题。 declval
的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_assert
。