问题 仍在评估废弃分支中的嵌套constexpr-if语句?


在我看来,在MSVC(版本15.7.3)中评估另一个constexpr-if语句的废弃分支内的constexpr-if语句。

请考虑以下代码:

#include <tuple>
#include <type_traits>

template <size_t I>
int test() {
    if constexpr(I != 0) {
        return 0;
    }
    else { // This branch is discarded, but it seems that the constexpr-if below is still evaulated?
        if constexpr(std::is_same_v<int, std::tuple_element_t<I, std::tuple<int>>>) { // some constexpr check that is valid only when I == 0
            return 1;
        }
        else {
            return 2;
        }
    }
}

int main() {
    test<1>();
    return 0;
}

上面的代码无法在MSVC中编译,因为 std::tuple_element_t 将失败的静态断言 I 超过了元组的界限。这表明,不管怎样,废弃分支中的代码也会被评估,即使它依赖于模板参数 I

根据 cppreference,constexpr-if要求“丢弃的陈述不能为每一种可能的专业化而形成错误”,但我很难确定这是否属于这种情况。

似乎GCC和Clang接受此代码没有问题(在Compiler Explorer上测试)。

编译错误是否可以被C ++标准接受,或者MSVC在此处不兼容?

(另外,如果标准不能保证我期望代码做什么,是否有另一种方法来完成嵌套的constexpr-if语句?)


5335
2018-06-14 12:13


起源

你怎么看? ;)更有可能的是,gcc和clang是错误的还是MSVC是对的? :) - Rakete1111
@ Rakete1111如果MSVC是对的,那么GCC和Clang也不错。也许标准不能保证是否必须评估嵌套的if-constexpr。 - Bernard
更简单的测试程序: coliru.stacked-crooked.com/a/524350fbd583874f - YSC
丢弃的语句不应该被实例化。标准说的很多。没有实例化它仍然在评估其中的东西似乎与我相矛盾。 MSVC很奇怪。 - StoryTeller
“对于每一种可能的专业化,废弃的陈述都不会形成错误” 丢弃的分支很好地形成 I == 0。 - Jarod42


答案:


gcc和clang是对的。这将是 非常 如果丢弃的分支中唯一未被丢弃的语句是另一个,则反直觉 if constexpr 声明。

[stmt.if] P2 没有提到任何相关的事情:

如果转换条件的值是 ,第一个子语句是 废弃的声明,否则是第二个子语句,如果   礼物,是一个 废弃的声明。在封闭模板实体的实例化期间(第17条),    如果条件在实例化后不依赖于值,那么 丢弃的子语句 (如果有的话)不是   实例化。

强调我的。标准说废弃的语句没有实例化,在你的情况下是 else { /*... * }。该分支中的任何内容都未实例化,因此不允许编译器实例化任何内容,因此实例化MSVC是错误的 std::tuple_element<I, std::tuple<int>>


12
2018-06-14 12:20