我们来看一个简单的例子:
#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;
克朗抱怨道:
错误:constexpr函数永远不会产生常量表达式 [-Winvalid-constexpr]
constexpr int main(int argc, char* argv[]) {
注意:非constexpr函数'运算符&lt;&lt; &GT;” 不能用于常量表达式
std::cout << "Hello!";
/usr/lib/gcc/x86_64-linux-gnu/4.8 /../../../../包括/ 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)];
有效!那一定是clang bug?我之所以说clang是因为gcc抱怨:
错误:constexpr函数的主体'constexpr int foo :: main(int, char **)'不是退货声明
所以我的结论是铿锵有误,而gcc是对的。
答案 0 :(得分:10)
Clang在这里是正确的。
第一个例子
这里的代码是:
constexpr int foo::main(int argc, char* argv[]) {
std::cout << argv[i];
return 0;
}
在C ++ 11 中,此代码格式错误,因为正文包含表达式语句,constexpr
中不允许这样做功能定义。
在C ++ 1y 中,此代码格式错误,无需诊断,因为对foo::main
的调用永远不会产生常量表达式(因为它总是调用{{1 },这不是operator<<(std::ostream&, const char*)
)。
第二个例子
在这种情况下,代码是:
constexpr
在C ++ 11 中,此代码格式错误,因为它包含constexpr int foo::main(int argc, char* argv[]) {
for (int i = 0; i < argc; i++)
std::cout << argv[i];
return 0;
}
- 语句。
在C ++ 1y 中,此代码有效。特别是,for
是一个常量表达式(值foo::main(0, 0)
)。由于0
可用于常量表达式,因此不允许Clang拒绝它,并且不会拒绝它。
第三个例子
foo::main
这里绑定的数组是 not 一个常量表达式(因为它读取int arr[foo::main(argc, argv)];
和argc
,它们不是常量)。但是,Clang默认支持可变长度数组作为扩展。您可以指定argv
将clang置于严格一致的模式,在该模式下它将拒绝此代码。
海湾合作委员会的诊断:
错误:constexpr函数的主体'constexpr int foo :: main(int,char **)'不是返回语句
在C ++ 11和C ++ 1y中都是不正确的。在C ++ 11中,它是不正确的,因为规则更加微妙(-pedantic-errors
函数的主体可以包含constexpr
s和一些其他结构,而不仅仅是typedef
- 语句)。在C ++ 1y中,规则根本不存在。
答案 1 :(得分:2)
您在C ++ 1y模式下编译代码,其中包含放宽constexpr
限制的措辞,包括所有循环语句。
查看引入这些更改的N3652。
答案 2 :(得分:0)
所以gcc 4.8.1没有实现轻松的constexpr限制,但是clang 3.5确实如此。我的错误是clang和gcc都有可变长度的数组扩展。如果我使用了std :: array,两个编译器都会拒绝代码。我仍然不明白的是,如果clang允许放松constexpr,那么为什么它不是constexpr?