在我看来,在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要求“废弃的陈述不能为每一种可能的专业化而形成错误”,但我很难确定这是否属于这种情况。 / p>
似乎GCC和Clang接受此代码没有问题(在Compiler Explorer上测试)。
C ++标准是否可以接受编译错误,或者MSVC在此处不兼容?
(另外,如果标准不能保证我期望代码做什么,是否有其他方法可以实现嵌套的constexpr-if语句?)
答案 0 :(得分:12)
gcc和clang是对的。如果丢弃的分支中唯一未被丢弃的语句是另一个if constexpr
语句,那么它将非常反直觉。
[stmt.if]p2没有提及任何相关内容:
如果转换条件的值为 false ,则第一个子语句是废弃语句,否则为第二个子语句,如果 present,是废弃的声明。在封闭模板实体的实例化期间(第17条), 如果条件在实例化后不依赖于值,那么丢弃的子语句(如果有的话)不是 实例强>
强调我的。标准说丢弃的语句没有实例化,在你的情况下是else { /*... * }
。该分支中的任何内容都未实例化,因此不允许编译器实例化任何内容,因此MSVC通过实例化std::tuple_element<I, std::tuple<int>>
是错误的。