以下代码在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

10-06 11:15