Мне кажется, что оператор 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, потому что std::tuple_element_t
не сможет std::tuple_element_t
статическое утверждение, если I
std::tuple_element_t
границы кортежа. Это говорит о том, что каким-то образом был оценен код в отброшенной ветки, даже если он зависит от параметра шаблона I
Согласно cppreference, constexpr-if требует, чтобы "отброшенное утверждение не могло быть плохо сформировано для любой возможной специализации", но мне сложно решить, имеет ли это место здесь.
Также кажется, что GCC и Clang принимают этот код без проблем (тестируются в Compiler Explorer).
Является ли ошибка компиляции приемлемой стандартом C++, или MSVC несовместим здесь?
(Кроме того, если то, что я ожидаю от кода, не гарантируется стандартом, есть ли другой способ выполнения вложенных операторов constexpr-if?)