std::declval() 在 GCC 中触发带有警告的断言错误

Posted

技术标签:

【中文标题】std::declval() 在 GCC 中触发带有警告的断言错误【英文标题】:std::declval() firing assertion error with warnings in GCC 【发布时间】:2013-07-06 09:46:00 【问题描述】:

考虑这个sn-p:

#include <utility>

template <typename U>
auto foo() -> decltype(std::declval<U>() + std::declval<U>());

template <typename T>
decltype(foo<T>()) bar(T)


int main()

    bar(1);
    return 0;

这会在使用-Wall -Wextra 编译时在我尝试过的所有 GCC 版本(4.7.3、4.8.1、4.9-some-git)中触发警告静态断言失败。例如,这是 4.8.1 的输出:

main.cpp: 在'decltype (foo()) bar(T) [with T = int; decltype (foo()) = int]': main.cpp:12:7: 从这里需要 main.cpp:8:2:警告:函数中没有返回语句返回非 void [-Wreturn-type] ^ 在 /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/move.h:57:0 包含的文件中, 来自 /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/stl_pair.h:59, 来自 /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/utility:70, 来自 main.cpp:1: /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits:在 'typename std::add_rvalue_reference >::type 的实例化中std::declval() [with _Tp = int;类型名 std::add_rvalue_reference >::type = int&&]': main.cpp:8:2: decltype (foo()) bar(T) [with T = int; decltype (foo()) = int]' main.cpp:12:7: 从这里需要 /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits:1871:7: 错误:静态断言失败:不能使用 declval()! static_assert(__declval_protector::__stop,

如果禁用警告bar提供返回语句,例如,

template <typename T>
decltype(foo<T>()) bar(T a)

    return a + a;

断言失败消失。 Clang++ 3.3 在任何情况下都不会触发断言错误。这是来自 GCC 的符合标准的行为吗?

【问题讨论】:

Can't reproduce. 嗯,不从具有非 void 返回类型的函数返回是未定义的行为,所以两个编译器都是正确的。 @AndyProwl:你向bar添加了一条语句。 @Kerrek SB:仍然,如果我包装 UB 使其实际上不会被执行,那么程序应该仍然是良好的格式吗?这与编译取消引用空指针的代码有什么不同?我的印象是 UB 仍然应该编译。 @KerrekSB:typeid(*a_nullptr) 根据标准抛出异常。 【参考方案1】:

只要我在函数中添加return ;throw;,我在6 月初构建的GCC 4.9 副本就可以毫无怨言地编译它。如果没有return,它会触发该静态断言。这当然是一个错误,但只是一个小错误,因为函数只会在执行时“崩溃”。

我在尝试在常量表达式中执行 declval() 时看到了该错误,因此在您的情况下可能会发生类似的情况。 “不能使用”大概是指ODR-use或使用结果。

也许在没有任何声明的情况下,它试图制造一个具有decltype 内容的声明。即使添加像0; 这样的简单语句也会消除虚假错误。 (但static_assert( true, "" ) 甚至void(0) 都不够用。)

提交了GCC bug。

【讨论】:

为提交错误干杯。【参考方案2】:

我不认为编译器没有编译该程序的权利;该程序的一个致命错误是 IME 不合格。 (警告,OTOH,非常好。编译器可以警告缺少返回语句、奇怪的继承习惯用法、标识符中的英式/美式拼写或字符串文字中的种族主义 cmets,只要它实际编译有效程序。)

我相信您的程序在运行时会产生未定义的行为,因为您无条件地执行了一个无法返回值的函数。但是,我认为这不能成为编译器实际编译该程序的借口。据它所知,你编译程序,将可执行文件复制到磁带备份中,然后再也不看它了。此外,我预计如果编译器为该程序发出错误,它可能会为在检查argc==1 后仅调用bar() 的程序发出错误,这肯定不属于编译器的 UB 权限。

严格来说,编译器不必在所有情况下都符合才能被视为符合。一个符合标准的编译器只需要能够编译任何有效的 C++ 程序。由于您可以在没有-Wall 的情况下编译该程序,因此可以说GCC 在没有传递该标志的情况下是一致的。令人惊讶的是,启用警告会导致不合格错误,因此我倾向于将其描述为 GCC 中的一致性问题。

【讨论】:

@Potatoswatter 在我的估计中

以上是关于std::declval() 在 GCC 中触发带有警告的断言错误的主要内容,如果未能解决你的问题,请参考以下文章

C++ std::function 参数 const 参考

在 Windows 10 中触控笔未触发 InkCanvas 事件

GitLab CI 如何在 Maven 多模块项目中触发子模块的管道

具有特征的 C++ 类型擦除

当选中父级时,如何在Kendo TreeView中触发子节点的onCheck事件

发带詹又回来啦