Как вернуть одно из нескольких значений из одного оператора return C ++? - PullRequest
1 голос
/ 05 мая 2020
return a or b or c or d;

Этот оператор возвращает либо true, либо false в C ++, и я знаю причину этого.

Но мне нужен обходной путь, чтобы я мог вернуть первый ненулевое значение значение через этот оператор возврата (или что-то подобное) , как это происходит в Python.

Я не ищу условные операторы, поскольку они выглядит неаккуратно иногда .

В принципе, можно ли сократить следующий код с помощью макроса или чего-то еще?

int fun(int a, int b, int c, int d)
{
    return a ? a : b ? b : c ? c : d;
}

Ответы [ 2 ]

4 голосов
/ 05 мая 2020

Я бы написал функцию так:

int fun(int a, int b, int c, int d) {
    if (a) return a;
    else if (b) return b;
    else if (c) return c;
    return d;
}

Она чистая и короткая. Я мог бы остановиться здесь, но давайте посмотрим, что можно сделать ...

Существует алгоритм, который уже почти делает то, что вы хотите. Небольшая модификация решения в этом ответе :

#include <algorithm>
#include <initializer_list>

template <typename T>
T first_non_zero_or_zero(const std::initializer_list<T>& args)
{
    auto it = std::find_if_not(args.begin(),args.end(),[](auto v){ return v==0;});    
    return (it != args.end()) ? *it : 0;
}

Недостаток использования функции для логических выражений не в корне. Если вы вызываете функцию через:

auto x = first_non_zero_or_zero( { foo(), expensive_function() });

, то должен вызываться expensive_function, независимо от того, что возвращает foo. Способ восстановить возможность короткого замыкания состоит в том, чтобы вместо этого передать вызываемые объекты, это будет

template <typename F>
auto first_non_zero_or_zero(F f){ return f();}

template <typename First,typename...F>
auto first_non_zero_or_zero(First f,F... others){    
    if (auto temp = f()) return temp;
    return first_non_zero_or_zero(others...);
}

int foo(){ return 0;}
int expensive_function(){ return 42;}

int main()
{
    std::cout << first_non_zero_or_zero(foo,expensive_function);
    return 0;
}

Однако это сделает вызовы излишне подробными при вызове с простым int s, так как вам нужно обернуть их в вызываемом:

int fun(int a,int b,int c) {
    first_non_zero( [](){ return a;},
                    [](){ return b;},
                    [](){ return c;})
}

Заключение: не усложняйте вещи более необходимыми. Функции должны делать одно. Единственное, что делает ваш fun, - это возвращает первое ненулевое из 4 целых чисел, и if-else - самый простой способ сделать это.

4 голосов
/ 05 мая 2020

Задачу можно выполнить, используя необходимую функцию в операторе return.

Например, вместо макроса я использовал шаблонную функцию , которая принимает параметры из std::initializer_list:

template <typename T>
T OR(const std::initializer_list<T>& args)
{
    for (const T& arg : args)
        if (arg)
            return arg;
    return T{};
}

Его можно использовать для данной проблемы следующим образом:

return OR({a, b, c, d});

Проблема в этой ссылке также может быть решена следующим образом:

return OR({(m + s - 1) % n, n});

Обратите внимание, что это зависит от неявного логического преобразования данного типа T. Так, например, пустой std::string не false. Кроме того, определяемый пользователем тип должен иметь operator bool() const, чтобы соответствовать этому обходному пути.

PS Пока я пытался задать свою ошибку в вариативном решении шаблона c в вопросе, Я сам обнаружил это решение: P

Примечание:

См. этот ответ, чтобы узнать об ограничениях этого способа при работе с другими сложные конструкции.

...