c++ - 是否允许在 std::declval<T> 上使用 decltype (函数本身,而不是调用它的结果)?

标签 c++ c++11 language-lawyer

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

相关文章:

c++ - 外部内联函数在所有翻译单元中必须具有相同的地址。这到底是如何实现的?

c - C 标准是否允许为指针分配任意值并递增它?

c++ - 专门化具有 decltype 尾随返回类型的函数模板

c++11 - 远程GDB session "Command Aborted"

c++ - std::pow 在 32 位和 64 位应用程序中产生不同的结果

c++ - 如果函数在匿名命名空间中声明,是否可以在全局命名空间中定义?

c - 隐式指针到 Const-T 转换

c++ - For循环不更新结构对象

c++ - 如何更改 boost 线程限制?

c++ - 从 const 映射中读取的惯用 C++