Должен ли я включать constexpr после else-if?
Вдохновленный этим ответом, я попытался скопировать и вставить (и добавить тестирование в main()
) этот код:
template<typename T>
std::tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
}
int main() {
auto [x, y] = foo("");
std::cout << x << " " << y;
}
Это очень просто - если T
выводится как int
, мы хотим вернуть кортеж [a, 0.0]
. Если T
выводится как double
, мы хотим вернуть кортеж [0, a]
. В противном случае мы хотим вернуть [0, 0.0]
.
Как вы можете видеть, в функции main()
я вызываю foo
с аргументом const char*
, что должно привести к тому, что x
и y
будут 0
. Это не тот случай.
При попытке скомпилировать я обнаружил странную ошибку:
error: could not convert '{0, a}
' from '<brace-enclosed initializer list>
' to 'std::tuple<int, double>
'
И я был как что? С какой стати я хочу этого... Я специально использовал std::is_same
, чтобы включить return {0, a}
только, когда тип a
определяется как double
.
Поэтому я быстро перешел к cppreference на if-constexpr. Внизу страницы, над Notes, мы можем увидеть этот фрагмент кода:
extern int x; // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}
Я подумал про себя. Я не могу понять, что не так с оригинальным кодом. Они используют один и тот же синтаксис и семантику....
Но мне было любопытно. Мне было любопытно, может ли что-то странное (в то время) решить эту проблему, поэтому я изменил исходный код на:
template<typename T>
std::tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if constexpr (std::is_same_v<double, T>) // notice the additional constexpr here
return {0, a};
else
return {0, 0.0};
}
int main() {
auto [x, y] = foo("");
std::cout << x << " " << y;
}
И вуаля! Код скомпилирован и выполнен как ожидалось. Итак, мой вопрос - Нужно ли ставить constexpr
после каждого оператора if
в операторе if-else
в подобных ситуациях? Или это просто мой компилятор? Я использую GCC 7.3.
Ответы
Ответ 1
Нужно ли добавлять constexpr после каждого оператора if в блоке if-else в таких ситуациях?
Да. Блок else-if 1 является ложью :), есть только если блоки 1 и еще блоки 1. Вот как ваш код просматривается компилятором:
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else // {
if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
// }
else if (/*...*/)
- это просто соглашение о форматировании, которое все используют. Таким образом, вы можете ясно видеть, что constexpr
второй constexpr
.
1: "блок" не является правильной терминологией. if является выражением (с дополнительной частью else). Блок {/*...*/}
.