丢弃分支中的嵌套 constexpr-if 语句仍在计算?

Nested constexpr-if statement in discarded branch is still evaluated?

提问人:Bernard 提问时间:6/14/2018 更新时间:6/14/2018 访问量:1137

问:

在我看来,在 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 中编译,因为当超过元组的边界时,静态断言将失败。这表明以某种方式也评估了丢弃分支中的代码,即使它依赖于 template 参数。std::tuple_element_tII

根据 cppreference,constexpr-if 要求“对于每个可能的专业化,丢弃的语句不能格式错误”,但我很难确定这里是否是这种情况。

GCC 和 Clang 似乎也毫无问题地接受此代码(在 Compiler Explorer 上测试)。

编译错误是否符合 C++ 标准,还是此处不符合 MSVC?

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

C++ 嵌套 C++17 if-constexpr

评论

3赞 Rakete1111 6/14/2018
你觉得怎么样?;)gcc 和 clang 是错误的还是 MSVC 是正确的,更有可能是什么?:)
0赞 Bernard 6/14/2018
@Rakete1111 好吧,如果 MSVC 是对的,GCC 和 Clang 不一定是错的。也许该标准没有对是否必须计算嵌套的 if-constexpr 做出任何保证。
0赞 YSC 6/14/2018
测试程序更简单:coliru.stacked-crooked.com/a/524350fbd583874f
0赞 StoryTeller - Unslander Monica 6/14/2018
不应实例化丢弃的语句。标准说了这么多。不实例化它并仍然评估其中的内容对我来说似乎是矛盾的。MSVC很奇怪。
1赞 Jarod42 6/14/2018
“对于每个可能的专业,被丢弃的陈述都不能是错误的”丢弃的分支对于 来说是很好的。I == 0

答:

13赞 Rakete1111 6/14/2018 #1

GCC 和 Clang 是对的。如果丢弃的分支中唯一没有被丢弃的语句是另一个语句,那将是非常违反直觉的。if constexpr

[stmt.if]p2 没有提到任何关于这一点的内容:

如果转换条件的值为 false,则第一个子语句是丢弃的语句,否则第二个子语句,如果 present,是被丢弃的语句。在封闭的模板化实体(第 17 条)的实例化过程中,如果条件在实例化后不依赖于值,则丢弃的子语句(如果有)不是 实例。

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