Нужно ли ставить constexpr после else-if? - PullRequest
0 голосов
/ 16 сентября 2018

Вдохновленный этим ответом , я пытался скопировать и вставить (и добавить тестирование в 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. Это не так .

При попытке его скомпилировать я обнаружил странную ошибку:

ошибка: не удалось преобразовать '{0, a}' из '<brace-enclosed initializer list>' в '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 Ответ

0 голосов
/ 16 сентября 2018

Нужно ли ставить 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.


1 : «блок» не является правильной терминологией. if - это утверждение (с необязательной частью else). Блок { /*...*/ }.

...