丢弃分支中的嵌套 constexpr-if 语句是否仍被评估?
Nested constexpr-if statement in discarded branch is still evaluated?
在我看来,另一个 constexpr-if 语句的丢弃分支内的 constexpr-if 语句在 MSVC(版本 15.7.3)中被评估。
考虑以下代码:
#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 中编译,因为当 I
超出元组的边界时,std::tuple_element_t
将导致静态断言失败。这表明以某种方式也评估了丢弃分支中的代码,即使它依赖于模板参数 I
.
根据 cppreference,constexpr-if 要求 "the discarded statement can't be ill-formed for every possible specialization",但我很难确定这里是否属于这种情况。
GCC 和 Clang 似乎也毫无问题地接受了这段代码(在 Compiler Explorer 上测试过)。
编译错误是否符合 C++ 标准,或者 MSVC 不兼容?
(此外,如果标准不保证我期望代码执行的操作,是否有另一种方法来完成嵌套的 constexpr-if 语句?)
gcc 和 clang 是对的。如果被丢弃的分支中唯一没有被丢弃的语句是另一个 if constexpr
语句,那将是 非常 违反直觉的。
[stmt.if]p2 没有提及任何相关内容:
If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if
present, is a discarded statement. During the instantiation of an enclosing templated entity (Clause 17),
if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not
instantiated.
强调我的。该标准表示丢弃的语句未实例化,在您的情况下是 else { /*... * }
。该分支中的任何内容都未实例化,因此不允许编译器实例化任何内容,因此 MSVC 通过实例化 std::tuple_element<I, std::tuple<int>>
.
是错误的
在我看来,另一个 constexpr-if 语句的丢弃分支内的 constexpr-if 语句在 MSVC(版本 15.7.3)中被评估。
考虑以下代码:
#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 中编译,因为当 I
超出元组的边界时,std::tuple_element_t
将导致静态断言失败。这表明以某种方式也评估了丢弃分支中的代码,即使它依赖于模板参数 I
.
根据 cppreference,constexpr-if 要求 "the discarded statement can't be ill-formed for every possible specialization",但我很难确定这里是否属于这种情况。
GCC 和 Clang 似乎也毫无问题地接受了这段代码(在 Compiler Explorer 上测试过)。
编译错误是否符合 C++ 标准,或者 MSVC 不兼容?
(此外,如果标准不保证我期望代码执行的操作,是否有另一种方法来完成嵌套的 constexpr-if 语句?)
gcc 和 clang 是对的。如果被丢弃的分支中唯一没有被丢弃的语句是另一个 if constexpr
语句,那将是 非常 违反直觉的。
[stmt.if]p2 没有提及任何相关内容:
If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity (Clause 17), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.
强调我的。该标准表示丢弃的语句未实例化,在您的情况下是 else { /*... * }
。该分支中的任何内容都未实例化,因此不允许编译器实例化任何内容,因此 MSVC 通过实例化 std::tuple_element<I, std::tuple<int>>
.