std :: declval()触发断言错误,并在GCC中发出警告

时间:2013-07-08 22:40:38

标签: c++ gcc c++11

请考虑以下代码段:

#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的符合标准的行为吗?

2 个答案:

答案 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中的一致性问题。