请考虑以下代码段:
#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;
}
这会在使用{{1}编译的所有GCC版本中发出警告和静态断言失败(4.7.3,4.8.1,4.9-some-git) }。例如,这是4.8.1的输出:
main.cpp: In instantiation of ‘decltype (foo<T>()) bar(T) [with T = int; decltype (foo<T>()) = int]’: main.cpp:12:7: required from here main.cpp:8:2: warning: no return statement in function returning non-void [-Wreturn-type] {} ^ In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/move.h:57:0, from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/bits/stl_pair.h:59, from /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/utility:70, from main.cpp:1: /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits: In instantiation of ‘typename std::add_rvalue_reference< <template-parameter-1-1> >::type std::declval() [with _Tp = int; typename std::add_rvalue_reference< <template-parameter-1-1> >::type = int&&]’: main.cpp:8:2: required from ‘decltype (foo<T>()) bar(T) [with T = int; decltype (foo<T>()) = int]’ main.cpp:12:7: required from here /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.1/include/g++-v4/type_traits:1871:7: error: static assertion failed: declval() must not be used! static_assert(__declval_protector::__stop,
如果使用return语句禁用警告或提供-Wall -Wextra
,例如,
bar
断言失败消失了。在任何情况下,Clang ++ 3.3都不会触发断言错误。这是GCC的符合标准的行为吗?
答案 0 :(得分:5)
只要我在函数中添加return {};
或throw;
,我在6月初制作的GCC 4.9副本就会毫无怨言地编译它。没有return
,它会触发静态断言。这肯定是一个错误,但只是一个小错误,因为该功能只在执行时“崩溃”。
我在尝试在常量表达式中执行declval()
时看到了这个错误,所以在你的情况下可能会发生类似的事情。 “不能使用”可能是指使用ODR或使用结果。
也许在没有任何声明的情况下,它试图用decltype
的内容制作一个声明。甚至添加像0;
这样的简单语句也会使虚假错误无效。 (但static_assert( true, "" )
甚至void(0)
不足。)
提交GCC bug。
答案 1 :(得分:2)
我不相信编译器无权编译该程序;这个程序的致命错误是,IME,不合格。 (警告,OTOH,非常好。编译器可以警告缺少返回语句,奇怪的继承习语,标识符中的英/美拼写,或字符串文字中的种族主义评论,如果它需要,只要它实际编译有效的程序。)
我相信您的程序在运行时会产生未定义的行为,因为您无条件地执行了无法返回值的函数。但是,我不认为借助编译器实际编译该程序;据他所知,你编译程序,将可执行文件复制到磁带备份,再也不用看了。另外,我希望如果编译器为这个程序发出错误,它可能会在检查bar()
之后为只调用argc==1
的程序发出错误,而且肯定不会在编译器中UB权利。
严格地说,编译器在所有情况下都不一定要符合要求。一致的编译器只需要能够编译任何有效的C ++程序。由于您可以在没有-Wall
的情况下编译此程序,因此可以认为GCC符合条件而没有传递该标志。令人惊讶的是,启用警告会导致不合格的错误,因此我倾向于将其描述为GCC中的一致性问题。