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;
}
1
Ardent Coder 5 Май 2020 в 12:15

2 ответа

Лучший ответ

Я бы написал функцию следующим образом:

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, поскольку вам нужно обернуть их в вызываемый:

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

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

2
idclev 463035818 5 Май 2020 в 10:35

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

Например, вместо макроса я использовал шаблонную функцию , которая принимает параметры из 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, чтобы соответствовать этому обходному пути.

< EM> P.S . Пока я пытался задать свою ошибку в вариационном шаблонном решении в вопросе, я сам обнаружил это решение: P

< Сильный > Примечание :

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

3
Ardent Coder 5 Май 2020 в 11:23