当前位置: 首页 > 知识库问答 >
问题:

Clang中的Constexpr错误但不是gcc中的错误?

鱼安然
2023-03-14

让我们举一个简单的例子:

#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函数永远不会产生常量html" target="_blank">表达式[-Wvalid-Constexpr]

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

注意:非constexpr函数'运算符

    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)];

真管用!那一定是叮当响的虫子?我之所以说铿锵是因为gcc抱怨:

错误:constexpr函数的主体'constexpr int foo::main(int, char**)'not a return-语句

所以我的结论是clang是错误的,而gcc是正确的。

共有3个答案

呼延晋
2023-03-14

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

孙鑫鹏
2023-03-14

您可以在C 1y模式下编译代码,该模式包含放宽constepr限制的措辞,包括所有循环语句。

看看引入这些变化的N3652。

楚权
2023-03-14

叮当声在这里是正确的。

第一个例子

这里的代码是:

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

在C 11中,此代码格式错误,因为正文包含一个表达式语句,这在consionexpr函数定义中是不允许的。

在C 1y中,此代码格式不正确,不需要进行诊断,因为调用foo::main永远无法生成常量表达式(因为它总是调用运算符)

第二个例子

在这种情况下,代码是:

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

在C 11中,此代码的格式不正确,因为它包含一个for-语句。

在C1Y中,此代码是有效的。尤其是,foo::main(0,0)是一个常量表达式(带有值0)。由于foo::main在常量表达式中可用,因此不允许Clang拒绝它,也不允许Clang拒绝它。

第三个例子

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

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

GCC的诊断:

错误:constexpr函数的主体'constexpr int foo::main(int, char**)'not a return-语句

在C 11和C 1y中都不正确。在C 11中,这是不正确的,因为规则更微妙(constepr函数的主体可以包含typedefs和一些其他构造,而不仅仅是return-语句)。在C1Y中,这个规则根本不存在。

 类似资料:
  • 考虑上面的代码,结果在这里。处的引用绑定受以下规则约束: 否则,该引用应为对非易失常数类型的左值引用(即cv1应为常数),或该引用应为右值引用。 如果初始化表达式 是右值(但不是位字段)或函数左值,并且"cv1 T1"与"cv2 T2"引用兼容,或 具有类类型(即T2是类类型),其中T1与T2不相关,并且可以转换为右值或函数左值类型cv3 T3,其中cv1 T1与cv3 T3引用兼容(参见[ove

  • 问题内容: 我为正在编写的Java程序定义了两个类,分别称为Class1和Class2。在Class1的构造函数主体中,我调用了class 2的构造函数。但是,出现编译错误 我尝试使用谷歌搜索此错误,但在任何地方都找不到有关此确切错误的任何讨论,因此我想我会将其发布到堆栈交换中。 有人可以解释这是什么类型的错误吗?class1和class2都非常简单:都只有一个构造函数方法,在两种情况下都将JSO

  • 此代码为-O1和-O2提供不同的结果: 那么这是一个错误吗?或者其中是否存在某种未定义的行为,编译器有权为其提供不同的结果? 据我从C99标准中可以看出,遍历所有值的循环是有效的,因为最大无符号整数值的增量被很好地定义为导致零。 涉及无符号操作数的计算永远不会溢出,因为不能由结果无符号整数类型表示的结果将被减少为比结果类型可以表示的最大值大一的数的模。

  • 我有一个<code>std::tuple</code>,其中填充了从类模板实例化的对象和一个类型参数。现在我想在编译时从元组中获取一个具有指定类型参数的元素。代码如下: 这在gcc 4.8.4上编译正常,但在vs2015u2上不行。错误在中,它说: 错误 C2131:表达式未计算为常量 注意:失败是由非常量参数或对非常量符号的引用引起的, 请参阅“I”的用法 显然,编译器认为返回值不是conste

  • 每次运行我的代码时,我都会从Cron那里得到以下错误,看起来它来自DateTime,是DateTime有错误还是我没有正确使用它。错误的第24行是这样的:- 我在$datetrue中给DateTime的是2014-06-13 13:00:00 致命错误:未捕获异常“exception”,消息为“DateTime::u construct():无法分析位置11(2)处的时间字符串(2014-06-1

  • 我的任务是创建一个名为MyRectangle的类来表示矩形。 所需的数据字段是宽度、高度和颜色。宽度和高度使用双数据类型,颜色使用字符串。然后编写一个程序来测试MyRectangle类。在客户端程序中,创建两个MyRectangle对象。为两个对象中的每一个指定宽度和高度。将第一个对象指定为红色,将第二个对象指定为黄色。显示两个对象的所有属性,包括其面积。 我已经写了所有的东西,没有错误,但是无论