【问题标题】:constexpr bug in clang but not in gcc?clang中的constexpr错误但gcc中没有?
【发布时间】:2014-02-27 16:41:51
【问题描述】:

让我们举个简单的例子:

#include <iostream>

namespace foo {
    constexpr int main(int argc, char* argv[]) {
      // code
    }
}

int main(int argc, char* argv[])
{
    return foo::main(argc, argv);
}

取决于 code 是什么,clang 会抱怨或不抱怨。如果代码是:

cout << "Hello!";
return 0;

clang 抱怨:

错误:constexpr 函数从不产生常量表达式 [-Winvalid-constexpr]

constexpr int main(int argc, char* argv[]) {

注意:非 constexpr 函数 'operator' 不能在常量表达式中使用

    std::cout << "Hello!";

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:530:5: 注意:此处声明

operator<<(basic_ostream<char, _Traits>& __out, const char* __s)

正如我们所知,constexpr 函数不能包含任何 cout 语句。但是如果我们这样做会发生什么?

  for (int i = 0; i < argc; i++)
    std::cout << argv[i];

clang 允许它!好的,但这不可能是一个 constexpr 函数,即使它被标记为 constexpr,让我们尝试在 constexpr 上下文中使用它。

int arr[foo::main(argc, argv)];

有效!所以一定是cla​​ng bug?我之所以说 clang 是因为 gcc 抱怨:

错误:constexpr 函数体 'constexpr int foo::main(int, char**)' 不是返回语句

所以我的结论是clang是错的,gcc是对的。

【问题讨论】:

  • 在 clang 3.4 上生成“constexpr 函数中不允许的语句”。
  • 你用的是什么版本的clang?
  • 我正在使用 clang 3.5 std=c++1y
  • 我什至不认为 clang 通常允许 constexpr
  • @ToryWebster 那么你为什么要标记这个c++11?您的问题的答案取决于它。

标签: c++ clang constexpr c++14


【解决方案1】:

您在 C++1y 模式下编译代码,其中包含放宽 constexpr 限制的措辞,包括所有循环语句。

查看引入这些更改的 N3652

【讨论】:

  • cout上允许它使用operator&lt;&lt;的具体地方在哪里?
  • @Griwes 我忽略了 for 循环的主体,因为我认为 OP 特别想知道循环。但是,是的,这很奇怪。
【解决方案2】:

所以 gcc 4.8.1 没有实现宽松的 constexpr 约束,但是 clang 3.5 可以。我的错误是 clang 和 gcc 都有可变长度的数组扩展。如果我改用 std::array ,两个编译器都会拒绝该代码。我仍然不明白的是,如果clang允许宽松的constexpr,那么为什么它不是constexpr?

【讨论】:

  • 因为operator&lt;&lt; 不是 constexpr。
  • 我建议至少使用-pedantic 进行编译以避免这种情况。
【解决方案3】:

这里的 Clang 是正确的。

第一个例子

这里,代码是:

constexpr int foo::main(int argc, char* argv[]) {
  std::cout << argv[i];
  return 0;
}

在 C++11 中,此代码格式错误,因为主体包含 表达式语句,而 constexpr 函数定义中不允许这样做.

在 C++1y 中,此代码格式错误,无需诊断,因为对 foo::main 的调用永远不会产生常量表达式(因为它总是调用 operator&lt;&lt;(std::ostream&amp;, const char*),它不是constexpr)。

第二个例子

在这种情况下,代码是:

constexpr int foo::main(int argc, char* argv[]) {
  for (int i = 0; i < argc; i++)
    std::cout << argv[i];
  return 0;
}

在 C++11 中,这段代码格式不正确,因为它包含 for-statement。

在 C++1y 中,此代码有效。特别是,foo::main(0, 0) 是一个常量表达式(值为0)。由于foo::main 可用于常量表达式,因此 Clang 不允许拒绝它,并且不会这样做。

第三个例子

int arr[foo::main(argc, argv)];

这里绑定的数组不是常量表达式(因为它读取argcargv,它们不是常量)。但是,默认情况下,Clang 支持可变长度数组作为扩展。您可以指定 -pedantic-errors 将 clang 置于严格符合模式,在该模式下它将拒绝此代码。

GCC 的诊断:

错误:constexpr 函数的主体 'constexpr int foo::main(int, char**)' 不是返回语句

在 C++11 和 C++1y 中都不正确。在 C++11 中,这是不正确的,因为规则更加微妙(constexpr 函数的主体可以包含 typedefs 和一些其他构造,而不仅仅是 return-statements)。在 C++1y 中,这个规则已经完全不存在了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 2015-12-23
    • 2022-10-18
    • 1970-01-01
    • 2019-05-03
    • 2017-10-12
    相关资源
    最近更新 更多