首页 文章

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

提问于
浏览
3

请考虑以下代码段:

#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;
}

这会在所有版本的GCC中发出警告和静态断言失败,我在使用 -Wall -Wextra 编译时尝试了它(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语句提供 bar ,例如,

template <typename T>
decltype(foo<T>()) bar(T a)
{
    return a + a;
}

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

2 回答

  • 4

    只要我在函数中添加 return {};throw; ,我在6月初制作的GCC 4.9副本就会毫无怨言地编译它 . 没有 return ,它会触发静态断言 . 这肯定是一个错误,但只是一个小错误,因为该函数只在执行时"crashes" .

    我在尝试在常量表达式中执行 declval() 时看到了这个错误,所以在你的情况下可能会发生类似的事情 . "cannot be used"可能是指使用ODR或使用结果 .

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

    提起了GCC bug .

  • 2

    我不相信编译器无权编译该程序;这个程序的致命错误是,IME,不合格 . (警告,OTOH,非常好 . 编译器可以警告错误的返回语句,奇怪的继承习语,标识符中的英/美拼写,或字符串文字中的种族主义评论,如果它需要,只要它实际编译有效的程序 . )

    我相信你的程序在运行时会产生未定义的行为,因为你无条件地执行了一个无法返回值的函数 . 但是,我不认为借助编译器实际编译该程序;据他所知,你编译程序,将可执行文件复制到磁带备份,再也不用看了 . 另外,我希望如果编译器为这个程序发出错误,它可能会在检查 argc==1 后只调用 bar() 的程序发出错误,并且肯定不会在编译器的UB权限范围内 .

    严格来说,编译器在所有情况下都不一定要符合要求 . 符合标准的编译器只需要能够编译任何有效的C程序 . 由于您可以在没有 -Wall 的情况下编译此程序,因此可以认为GCC符合条件而没有传递该标志 . 令人惊讶的是,启用警告会导致不合格的错误,因此我倾向于将此表征为GCC中的一致性问题 .

相关问题