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 的输出:
如果禁用警告或为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 中触发带有警告的断言错误的主要内容,如果未能解决你的问题,请参考以下文章
在 Windows 10 中触控笔未触发 InkCanvas 事件
GitLab CI 如何在 Maven 多模块项目中触发子模块的管道