[英]What determines whether a constexpr function is a constant expression?
(compiler used is gcc with c++17 as far as I know (difficult to find this in visual studio)) (据我所知,使用的编译器是 gcc 和 c++17 (在 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';
}
The above code gives the error on compile:上面的代码给出了编译错误:
constexpr function 'f' cannot result in a constant expression. constexpr function 'f' 不能产生常量表达式。
As I understand it this is because the function increment
is not a constexpr.据我了解,这是因为 function increment
不是 constexpr。 What confuses me is that the following code compiles fine:让我感到困惑的是,以下代码编译得很好:
#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';
}
This code is functionally the same and it does compile, even though increment is still not a constexpr.这段代码在功能上是相同的,并且可以编译,即使增量仍然不是 constexpr。 I don't understand how it's possible that a for-loop through the range [0, 1) causes the compiler to realize that the function f
actually is a constexpr.我不明白通过范围 [0, 1) 的 for 循环如何导致编译器意识到 function f
实际上是 constexpr。
If anyone can give some insights on constexpr in c++ and this apparent inconsistency, I'd greatly appreciate it.如果有人可以对 c++ 中的 constexpr 和这种明显的不一致提供一些见解,我将不胜感激。
Both programs are "ill-formed no diagnostic required", per [dcl.constexpr]/6 :根据[dcl.constexpr]/6 ,这两个程序都是“格式错误,不需要诊断”:
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, an evaluated subexpression of the initialization full-expression of some constant-initialized object ( [basic.start.static] ), the program is ill-formed, no diagnostic required.对于既不是默认值也不是模板的 constexpr function 或 constexpr 构造函数,如果不存在参数值,则 function 或构造函数的调用可以是核心常量表达式的求值子表达式,或者,对于构造函数,求值子表达式一些常量初始化的 object ( [basic.start.static] ) 的初始化完整表达式,程序格式错误,不需要诊断。
It's a bit strange that gcc just fails to notice the issue with the second program, but it's still conforming.有点奇怪,gcc 只是没有注意到第二个程序的问题,但它仍然符合要求。
Note a diagnostic would be required if f
were used in a context that actually requires a constant expression, for example constexpr int n = f();
请注意,如果在实际需要常量表达式的上下文中使用f
,则需要进行诊断,例如constexpr int n = f();
. .
Some things are never permitted in a constexpr function.有些事情在 constexpr function 中是不允许的。 These do require a diagnostic (typically an error message), even if the function is never used in a constant expression - see cigien's answer .这些确实需要诊断(通常是错误消息),即使 function 从未在常量表达式中使用 - 请参阅cigien 的答案。 But the programs in the question don't violate any of these stricter rules.但是问题中的程序不违反任何这些更严格的规则。
Since you're not calling f
in a constant expression, your question is asking if the compiler is required to diagnose that f
can't be called in a constant expression, based solely on its definition .由于您没有在常量表达式中调用f
,因此您的问题是询问编译器是否需要仅根据其定义来诊断无法在常量表达式中调用f
。
The requirements on the definition of a constexpr
function are enumerated here :这里列举了对constexpr
function定义的要求:
The definition of a constexpr function shall satisfy the following requirements: constexpr function 的定义应满足以下要求:
(3.1) its return type (if any) shall be a literal type; (3.1) 其返回类型(如果有)应为文字类型;
(3.2) each of its parameter types shall be a literal type; (3.2) 其每个参数类型应为字面量类型;
(3.3) it shall not be a coroutine; (3.3) 不能是协程;
(3.4) if the function is a constructor or destructor, its class shall not have any virtual base classes; (3.4) 如果 function 是构造函数或析构函数,其 class 不得有任何虚拟基类;
(3.5) its function-body shall not enclose (3.5) 其函数体不得包含
(3.5.1) a goto statement, (3.5.1) goto 语句,
(3.5.2) an identifier label, (3.5.2) 标识符 label,
(3.5.3) a definition of a variable of non-literal type or of static or thread storage duration. (3.5.3) 非文字类型或 static 或线程存储持续时间的变量的定义。
As can be seen, the definition of f
does not violate any of the requirements in the list.可以看出, f
的定义没有违反列表中的任何要求。 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.正如aschepler 的回答中指出的那样,像f
这样的constexpr
函数不能在常量表达式中调用,但不能被诊断,被认为是格式错误的,不需要诊断。
You're not actually "calling" f
at compile time.您实际上并没有在编译时“调用” f
。
if your main function included: static_assert(f() == 1, "f() returned 1");
如果您的主要 function 包括: static_assert(f() == 1, "f() returned 1");
I suspect you would get an "f() is not a constant expression" error.我怀疑您会收到“f() 不是常量表达式”错误。
Here's a related question这是一个相关的问题
The standard requires that a constexpr
function actually be evaluable at compile time for some set of parameters but not all.该标准要求constexpr
function 实际上可以在编译时对某些参数集进行评估,但不是全部。 It does not require compilers to diagnose a constexpr
function doing certain things which might be non-compile-time in some circumstances, or even whether such a function has such a set of parameters.它不需要编译器来诊断constexpr
function 在某些情况下执行某些可能是非编译时的事情,甚至不需要编译器来诊断这样的 function 是否具有这样的一组参数。 This avoids them having to solve the halting problem.这避免了他们不得不解决停机问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.