13

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

gccclang都不会导致编译代码的问题。代码格式是否错误,或者实际上是否允许?

4

2 回答 2

6

在函数声明的情况下,说明constexpr符是对编译器的断言,声明的函数可以在常量表达式中求值,即可以在编译时求值的表达式。然而,声明内的对象初始化不需要constexpr在其声明说明符内具有常量表达式

更短:constexpr函数可能暗示常量表达式,但常量表达式初始化不需要相关声明具有constexpr说明符。

您可以在 C++ 标准 [dcl.constexpr] 中检查这一点:

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

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

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

表达式e是核心常量表达式,除非e [...]的评估将评估以下表达式之一[...]

声明不是表达式,因此被声明对象的初始化是一个常量表达式,无论声明中是否存在constexpr说明符。

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

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

当您声明constexpr int a编译器期望a由常量表达式初始化并且表达式foo({1,2})是常量表达式时,因此您的代码格式正确。

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

于 2017-09-17T07:20:20.387 回答
1

一个函数必须满足几个要求constexpr。函数体有一些要求,constexpr显示的代码似乎没有违反任何要求。关键是不要求函数中的每条语句都必须是constexpr. 这里唯一有趣的要求是:

至少存在一组参数值,因此函数的调用可以是核心常量表达式的求值子表达式(对于构造函数,在常量初始值设定项中使用就足够了)(C++14 起)。违反此项目符号不需要诊断。

注意最后一句话。编译器可能(但不是必须)抛出一个危险信号。

关键要求仅仅是函数有各种参数值,从而导致函数的结果恒定(并且函数体满足列出的要求)。例如,函数可能有条件地使用结构化绑定;但是对于某些参数值集,请执行其他操作,从而产生恒定的结果。这将勾选此复选框的constexpr功能。

但是,尽管现代 C++ 编译器很复杂,但它们可能不一定能够在所有可能的情况下都达到这个决定,因此,在实践中,很难强制执行这样的要求,因此允许编译器仅将其作为的确。

于 2017-09-16T12:48:15.120 回答