Clang中的ConstexPR错误,但不在GCC中

constexpr bug in clang but not in gcc?

本文关键字:GCC 中的 ConstexPR 错误 Clang      更新时间:2023-10-16

让我们以这个简单的示例:

#include <iostream>
namespace foo {
    constexpr int main(int argc, char* argv[]) {
      // code
    }
}
int main(int argc, char* argv[])
{
    return foo::main(argc, argv);
}

取决于代码,clang会抱怨或否。如果代码是:

cout << "Hello!";
return 0;

clang抱怨:

错误:constexpr函数永远不会产生常数表达式 [-winvalid-constexpr]

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

注意:non-constexpr函数'运算符&lt;&lt;>' 不能在恒定表达式

中使用
    std::cout << "Hello!";

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../../包括/c /4.8/ostream:530:5:5:5: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)];

它有效!所以它一定是clang错误?我之所以说clang的原因是因为GCC抱怨:

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

所以我的结论是clang是错误的,而海湾合作od是正确的。

clang在此处是正确的。

第一个示例

在这里,代码为:

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

在C 11 中,此代码是不形式的,因为身体包含一个表达式statement ,在constexpr函数定义中不允许使用。<<<<<<<<<<<<<<

在C 1Y 中,此代码不需要诊断,因为foo::main的调用永远不会产生恒定的表达式(因为它总是调用operator<<(std::ostream&, 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陈述。

在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 **)'不是返回statement

在C 11和C 1Y中都是不正确的。在C 11中,这是不正确的,因为该规则更微妙(constexpr功能的主体可以包含typedef s和其他一些构造,而不仅仅是return列表)。在C 1Y中,该规则根本不再存在。

您以C 1Y模式编译代码,其中包含措辞放松constexpr限制,包括所有循环语句。

请查看引入这些更改的N3652。

因此,GCC 4.8.1不会实现放松的ConstexPr限制,但是Clang 3.5确实如此。我的错误是Clang和GCC都具有可变的长度阵列扩展。如果我使用std ::数组,则两个编译器都会拒绝代码。我仍然不明白的是,如果Clang允许放松的Constexpr,那么为什么不是Constexpr?