11

在我看来,在 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 语句?)

4

1 回答 1

13

gcc 和 clang 是对的。如果被丢弃分支中唯一未被丢弃的语句是另一条语句,那将是非常if constexpr违反直觉的。

[stmt.if]p2没有提及任何相关内容:

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

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

于 2018-06-14T12:20:05.733 回答