如果结构化绑定不能是constexpr,为什么它们可以在constexpr函数中使用?

W.F*_*.F. 12 c++ language-lawyer constexpr c++17 structured-bindings

根据这个答案,显然没有充分的理由说明为什么不允许结构化绑定是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);
}
Run Code Online (Sandbox Code Playgroud)

无论GCC不惹麻烦编译代码.代码是否格式不正确或实际允许这个?

Oli*_*liv 6

在函数声明的情况下,说明constexpr符是对编译器的断言,声明的函数可以在常量表达式中计算,即可以在编译时计算的表达式.然而,声明中的对象初始化不需要constexpr在其声明说明符中包含常量表达式.

更短:constexpr函数可能意味着常量表达式,常量表达式初始化不需要关联的声明具有constexpr说明符.

您可以在C++标准[dcl.constexpr]中进行检查:

对constexpr函数的调用产生与在所有方面调用等效的非constexpr函数相同的结果,除了

- 对constexpr函数的调用可以出现在常量表达式中[...]

这是对表达式的求值,该表达式确定表达式是否为常量表达式[expr.const]:

表达式Ë是核心常量表达式除非评价ë [...]将评估以下中的一个表达 [...]

声明不是表达式,因此声明的对象的初始化是一个常量表达式,而不管声明中是否存在constexpr说明符.

最后,在[dcl.constexpr]中,指定一个constexpr函数必须使得存在可以将其主体作为常量表达式求值的参数:

对于既不是默认也不是模板的constexpr函数或constexpr构造函数,如果不存在参数值,则函数或构造函数的调用可以是核心常量表达式的评估子表达式(8.20),或者对于构造函数,某些对象的常量初始化程序(6.6.2),程序格式错误,无需诊断.

当您声明constexpr int a编译器期望a通过常量表达式进行初始化并且表达式foo({1,2})是常量表达式时,您的代码就会很好地形成.

PS:尽管如此,函数局部变量声明中的声明说明符(static,thread_local => static)意味着无法声明该函数constexpr.