以下代码触发libstdc++上的静态断言:
#include <utility>
using t = decltype(std::declval<const void>);应该这样吗?
这个问题的动机:
下面的declval实现埃里克·尼布勒 (显然是编译时优化)
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)类型。
发布于 2016-05-19 02:33:38
解密规定:
如果该函数被odr使用(3.2),则程序的格式不正确.
基本上就是这样。就功能而言,odr--使用方式来自basic.def.odr。
如果它是一组重载函数(3.4、13.3、13.4)的唯一查找结果或选定的成员,则其名称显示为可能计算的表达式的函数被odr使用,除非它是一个纯虚拟函数,并且它的名称没有显式限定,或者该表达式形成指向成员的指针(5.3.1)。
但也包括:
除非表达式是未计算的操作数(第5条)或其子表达式,否则表达式可能被计算。
和dcl.type.simple
decltype说明符的操作数是未计算的操作数(第5条)。
因此,在decltype(std::declval<const void>)中,std::declval没有潜在的评估,因此它没有被odr使用。因为这是declval程序格式不正确的一个标准,而且我们没有满足它,我认为libstdc++发出静态断言是错误的。
虽然我不认为这是一个libstc++的事情。我认为更多的问题是何时触发static_assert。libstdc++实现declval是:
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>()),尽管我们在这两种情况下都处于未评估的上下文中。我怀疑这是一个bug,但它可能只是在标准中被低估了--触发static_assert的正确行为是什么。
https://stackoverflow.com/questions/37312668
复制相似问题