为什么 if constexpr 不会使这个核心常量表达式错误消失?

Why doesn't an if constexpr make this core constant expression error disappear?

本文关键字:常量 核心 表达式 错误 消失 constexpr if 为什么      更新时间:2023-10-16

参考此问题。用于初始化constexpr变量y的核心常数表达式不正确。给定的太多。

但是,如果我尝试将if变成if constexpr

template <typename T>
void foo() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1 << x;
    }
}
int main(){
    foo<int>();
}

错误仍然存在。GCC 7.2仍在给予:

error: right operand of shift expression '(1 << -1)' is negative [-fpermissive]

,但我认为应该将语义检查放在废弃的分支上。

通过constexpr lambda进行间接确实有帮助,但是:

template <typename T>
void foo(){
    constexpr int x = -1;
    constexpr auto p = []() constexpr { return x; };
    if constexpr (x >= 0){
        constexpr int y = 1<<p();
    }
}

y上的constexpr说明符似乎改变了如何检查丢弃的分支。这是预期的行为吗?


@max66 很友好,可以检查其他实现。他报告说,GCC(7.2.0/head 8.0.0)和clang(5.0.0/head 6.0.0)可重现该错误。

标准对 if constexpr丢弃语句的说法不多。关于这些:

,[stmt.if]中基本上有两个陈述
  1. 在封闭的模板中,丢弃的语句未实例化。
  2. 从废弃的语句中引用的名称不需要ODR定义。

这些都不适用于您的用法:编译器是正确的,如果初始化,则可以抱怨constexpr。请注意,当您想利用 Intantiation 失败时,您需要使条件取决于模板参数:如果值不依赖于模板参数,则当失败时发生故障模板是定义的。例如,此代码仍然失败:

template <typename T>
void f() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1<<x;
    }
}

但是,如果您使x取决于类型T,即使使用f实例化了int

,也可以
template <typename T>
void f() {
    constexpr T x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1<<x;
    }
}
int main() {
    f<int>();
}

请注意,对于constexpr丢弃的语句,如果:

对于每一个可能的专业化,都不能对废弃的说明进行不良形式:

要解决问题,您可以根据模板参数进行声明,例如

template<typename T, int X> struct dependent_value { constexpr static int V = X; };
template <typename T>
void foo() {
    constexpr int x = -1;
    if constexpr (x >= 0){
        constexpr int y = 1 << dependent_value<T, x>::V;
    }
}

live

我不确定为什么您希望不检查分支。如果分支是"未检查"的唯一时间是它是模板的一部分而不是实例化,则根据[stmt.if] p2:

在封闭模板的实例化期间 实体(第17条),如果条件在实例化后不取决于价值,则废弃的取代 (如果有)未实例化。

您的代码似乎不在适用的情况下。