根据this answer显然没有充分的理由说明为什么不允许结构化绑定是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);
}
答案 0 :(得分:6)
在函数声明的情况下,constexpr
说明符是对编译器的断言,声明的函数可以在常量表达式中计算,即可以是一个表达式在编译时评估。然而,声明中的对象初始化不需要在其声明说明符中包含constexpr
作为常量表达式。
更短:constexpr
函数可能意味着常量表达式,但常量表达式初始化不需要关联的声明具有constexpr
说明符。< / p>
您可以在C ++标准[dcl.constexpr]中查看:
对constexpr函数的调用产生与调用等效的非constexpr函数相同的结果 所有方面除了
- 对constexpr函数的调用可以出现在常量表达式[...]
中
这是表达式的评估,用于确定表达式是否为a 常量表达式[expr.const]:
表达式 e 是核心常量表达式,除非 e [...]的评估评估以下之一表达强> [...]
声明不是表达式,因此声明的对象的初始化是常量表达式,无论是否存在constexpr
说明符在声明中。
最后,在[dcl.constexpr]中,指定constexpr
函数必须是这样的,以便存在可以将其主体评估为常量表达式的参数:< / p>
对于既不是默认也不是模板的constexpr函数或constexpr构造函数,如果没有参数 存在这样的值,使得函数或构造函数的调用可以是被评估的子表达式 核心常量表达式(8.20),或者,对于构造函数,某个对象(6.6.2)的常量初始值设定项, 程序格式错误,无需诊断。
当您声明constexpr int a
时,编译器希望a
被常量表达式初始化,而表达式foo({1,2})
是一个常量表达式,因此您的代码形式良好。
PS:尽管如此,函数局部变量声明中的声明说明符(static,thread_local =&gt; static)意味着函数不能被声明为constexpr
。
答案 1 :(得分:1)
有several requirements that a constexpr
function must meet。 constexpr
函数的主体有一些要求,并且显示的代码似乎没有违反它们中的任何一个。关键点在于,不要求函数中的每个语句都必须是constexpr
。这里唯一有趣的要求就是这个:
存在至少一组参数值,使得a 函数的调用可以是a的一个被评估的子表达式 核心常量表达式(对于构造函数,在常量中使用) 初始化程序就足够了)(因为C ++ 14)。无需诊断 因为违反了这个子弹。
请注意最后一句话。编译器可能(但不是必须)抛出红色标记。
关键要求仅仅是函数中存在一些参数值,这些参数值会导致函数的常量结果(并且函数体符合列出的要求)。例如,函数可以有条件地使用结构化绑定;但是对于某些参数值集做其他事情,产生一个恒定的结果。这会勾选constexpr
函数的复选框。
但是,尽管现代C ++编译器的复杂性,它们可能不一定能够在每个可能的实例中达到这个决心,因此,在实践中,很难强制执行这样的要求,因此允许编译器只是认为这是理所当然的。