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

时间:2017-09-16 12:37:30

标签: c++ language-lawyer c++17 constexpr structured-bindings

根据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);
}

gccclang都不会导致编译代码时遇到问题。代码是不正确的,或者这个实际上是允许的吗?

2 个答案:

答案 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 meetconstexpr函数的主体有一些要求,并且显示的代码似乎没有违反它们中的任何一个。关键点在于,不要求函数中的每个语句都必须是constexpr。这里唯一有趣的要求就是这个:

  

存在至少一组参数值,使得a   函数的调用可以是a的一个被评估的子表达式   核心常量表达式(对于构造函数,在常量中使用)   初始化程序就足够了)(因为C ++ 14)。无需诊断   因为违反了这个子弹。

请注意最后一句话。编译器可能(但不是必须)抛出红色标记。

关键要求仅仅是函数中存在一些参数值,这些参数值会导致函数的常量结果(并且函数体符合列出的要求)。例如,函数可以有条件地使用结构化绑定;但是对于某些参数值集做其他事情,产生一个恒定的结果。这会勾选constexpr函数的复选框。

但是,尽管现代C ++编译器的复杂性,它们可能不一定能够在每个可能的实例中达到这个决心,因此,在实践中,很难强制执行这样的要求,因此允许编译器只是认为这是理所当然的。