以下代码在 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]规定:
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
没有潜在的评估,因此它没有被使用。由于这是 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
s。
关于c++ - 是否允许在 std::declval<T> 上使用 decltype (函数本身,而不是调用它的结果)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37312668/