mch*_*l12 29 c++ constexpr c++17
(据我所知,使用的编译器是带有 c++17 的 gcc(在 Visual Studio 中很难找到))
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
increment( v );
return v;
}
int main( )
{
cout << f( ) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
上面的代码给出了编译错误:
constexpr 函数 'f' 不能产生常量表达式。
据我了解,这是因为该函数increment不是 constexpr。让我困惑的是以下代码编译得很好:
#include <iostream>
using namespace std;
void increment( int& v )
{
++v;
}
int constexpr f()
{
int v = 0;
for( int i = 0; i < 1; ++i )
{
increment( v );
}
return v;
}
int main( )
{
cout << f( ) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
这段代码在功能上是相同的,它确实可以编译,即使 increment 仍然不是 constexpr。我不明白通过范围 [0, 1) 的 for 循环如何导致编译器意识到该函数f实际上是一个 constexpr。
如果有人可以对 C++ 中的 constexpr 和这种明显的不一致提供一些见解,我将不胜感激。
asc*_*ler 12
根据[dcl.constexpr]/6,这两个程序都是“格式错误的,不需要诊断” :
对于既不是默认值也不是模板的 constexpr 函数或 constexpr 构造函数,如果不存在参数值,使得函数或构造函数的调用可以是核心常量表达式的计算子表达式,或者对于构造函数,则为某些常量初始化对象([basic.start.static])的初始化完整表达式,程序格式错误,无需诊断。
gcc 只是没有注意到第二个程序的问题,这有点奇怪,但它仍然符合要求。
请注意,如果f在实际需要常量表达式的上下文中使用,则需要诊断,例如constexpr int n = f();。
有些东西在 constexpr 函数中是不允许的。这些确实需要诊断(通常是错误消息),即使函数从未在常量表达式中使用 - 请参阅cigien 的回答。但问题中的程序不违反任何这些更严格的规则。
由于您不是f在常量表达式中调用,因此您的问题是询问编译器是否需要f仅根据定义来诊断无法在常量表达式中调用的内容。
这里列举了对函数定义的要求:constexpr
constexpr 函数的定义应满足以下要求:
(3.1) 其返回类型(如果有)应为文字类型;
(3.2) 它的每个参数类型都应该是一个文字类型;
(3.3) 不应是协程;
(3.4) 如果函数是构造函数或析构函数,则其类不应有任何虚拟基类;
(3.5) 其功能体不得包含
(3.5.1) goto 语句,
(3.5.2) 标识符标签,
(3.5.3) a definition of a variable of non-literal type or of static or thread storage duration.
As can be seen, the definition of f does not violate any of the requirements in the list. So a compiler is conforming if it chooses not to diagnose this.
As pointed out in aschepler's answer, constexpr functions like f that can't be called in a constant expression, but are not diagnosable as such, are considered ill-formed-no-diagnostic-required.
| 归档时间: |
|
| 查看次数: |
1376 次 |
| 最近记录: |