6

考虑这个片段:

#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. 例如,这是 4.8.1 的输出:

main.cpp: 在 'decltype (foo<T>()) bar(T) [with T = int; decltype (foo<T>()) = 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< <template-parameter-1-1> >::type 的实例化中std::declval() [with _Tp = int; 类型名 std::add_rvalue_reference<<template-parameter-1-1> >::type = int&&]':
main.cpp:8:2: 'decltype (foo<T>()) bar(T) [with T = int; decltype (foo<T>()) = 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 的符合标准的行为吗?

4

2 回答 2

6

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

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

也许在没有任何声明的情况下,它试图制造一个具有decltype. 甚至添加一个简单的语句,如0;沉默虚假错误。(但static_assert( true, "" )甚至void(0)是不够的。)

提交了一个GCC 错误

于 2013-07-09T02:24:55.343 回答
2

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

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

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

于 2013-07-09T00:14:35.160 回答