如果结构化绑定不能是 constexpr 为什么可以在 constexpr 函数中使用它们?
If structured bindings cannot be constexpr why can they be used in constexpr function?
根据 显然没有充分的理由为什么不允许结构化绑定是 constexpr,但标准仍然禁止它。然而,在这种情况下,难道不应该也禁止在 constexpr 函数内使用结构化绑定吗?考虑一个简单的片段:
#include <utility>
constexpr int foo(std::pair<int, int> p) {
auto [a, b] = p;
return a;
}
int main() {
constexpr int a = foo({1, 2});
static_assert(a == 1);
}
有several requirements that a constexpr
function must meet个。 constexpr
函数的主体有一些要求,显示的代码似乎没有违反任何要求。关键是没有要求函数中的每条语句都必须是constexpr
。这里唯一有趣的要求是这个:
there exists at least one set of argument values such that an
invocation of the function could be an evaluated subexpression of a
core constant expression (for constructors, use in a constant
initializer is sufficient) (since C++14). No diagnostic is required
for a violation of this bullet.
注意最后一句话。编译器可能会(但不是必须)发出红旗。
关键要求仅仅是函数的参数值有一些分类,导致函数的结果恒定(并且函数体满足列出的要求)。例如,函数可能有条件地使用结构化绑定;但是对于某些参数值集做其他事情,产生一个恒定的结果。这将为 constexpr
函数勾选此复选框。
但是,尽管现代 C++ 编译器非常复杂,但它们不一定能够在所有可能的情况下都达到这种确定,因此,在实践中,很难强制执行这样的要求,因此允许编译器认为这是理所当然的。
在函数声明的情况下,constexpr
说明符是对编译器的断言,声明的函数可以在 常量表达式 中求值,即可以在编译时求值的表达式。尽管如此,声明中的对象初始化不需要在其声明说明符中包含 constexpr
成为 常量表达式 .
更短:constexpr
函数可能暗示常量表达式但是常量表达式初始化不需要关联的声明有一个constexpr
说明符。
您可以在 C++ 标准中查看 [[=55=]]:
A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in
all respects except that
— a call to a constexpr function can appear in a constant expression[...]
这是表达式的求值,用于确定表达式是否是
常量表达式 [expr.const]:
An expression e is a core constant expression unless the evaluation of e [...] would evaluate one of the following expression[...]
声明不是表达式,因此被声明对象的初始化是一个常量表达式,无论是否存在声明中的 constexpr
说明符。
最后,在 [dcl.constexpr] 中指定 constexpr
函数必须存在参数,其主体可以作为 常量表达式求值:
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 (8.20), or, for a constructor, a constant initializer for some object (6.6.2), the
program is ill-formed, no diagnostic required.
当您声明 constexpr int a
时,编译器期望 a
由常量表达式初始化,而表达式 foo({1,2})
是常量表达式,因此您的代码格式正确。
PS: 尽管如此,函数局部变量声明中的声明说明符(static, thread_local=>static) 意味着函数不能被声明constexpr
.
根据
#include <utility>
constexpr int foo(std::pair<int, int> p) {
auto [a, b] = p;
return a;
}
int main() {
constexpr int a = foo({1, 2});
static_assert(a == 1);
}
有several requirements that a constexpr
function must meet个。 constexpr
函数的主体有一些要求,显示的代码似乎没有违反任何要求。关键是没有要求函数中的每条语句都必须是constexpr
。这里唯一有趣的要求是这个:
there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression (for constructors, use in a constant initializer is sufficient) (since C++14). No diagnostic is required for a violation of this bullet.
注意最后一句话。编译器可能会(但不是必须)发出红旗。
关键要求仅仅是函数的参数值有一些分类,导致函数的结果恒定(并且函数体满足列出的要求)。例如,函数可能有条件地使用结构化绑定;但是对于某些参数值集做其他事情,产生一个恒定的结果。这将为 constexpr
函数勾选此复选框。
但是,尽管现代 C++ 编译器非常复杂,但它们不一定能够在所有可能的情况下都达到这种确定,因此,在实践中,很难强制执行这样的要求,因此允许编译器认为这是理所当然的。
在函数声明的情况下,constexpr
说明符是对编译器的断言,声明的函数可以在 常量表达式 中求值,即可以在编译时求值的表达式。尽管如此,声明中的对象初始化不需要在其声明说明符中包含 constexpr
成为 常量表达式 .
更短:constexpr
函数可能暗示常量表达式但是常量表达式初始化不需要关联的声明有一个constexpr
说明符。
您可以在 C++ 标准中查看 [[=55=]]:
A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in all respects except that
— a call to a constexpr function can appear in a constant expression[...]
这是表达式的求值,用于确定表达式是否是 常量表达式 [expr.const]:
An expression e is a core constant expression unless the evaluation of e [...] would evaluate one of the following expression[...]
声明不是表达式,因此被声明对象的初始化是一个常量表达式,无论是否存在声明中的 constexpr
说明符。
最后,在 [dcl.constexpr] 中指定 constexpr
函数必须存在参数,其主体可以作为 常量表达式求值:
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 (8.20), or, for a constructor, a constant initializer for some object (6.6.2), the program is ill-formed, no diagnostic required.
当您声明 constexpr int a
时,编译器期望 a
由常量表达式初始化,而表达式 foo({1,2})
是常量表达式,因此您的代码格式正确。
PS: 尽管如此,函数局部变量声明中的声明说明符(static, thread_local=>static) 意味着函数不能被声明constexpr
.