Выполнение рекурсивных вызовов функции Variadic против простых операторов if..else - PullRequest
0 голосов
/ 24 января 2019

Я надеюсь, что предмет отражает то, что я хочу спросить здесь ... Я приложил все усилия.

Мы должны установить определенные переменные на основе нескольких условий во время выполнения.Мы всегда делали заявления if..else, но я считаю их слишком громоздкими, особенно если учесть, что может быть несколько условий.Я попытался разработать что-то, используя возможности c ++ 11/17, и придумал следующее.

Итак, мой вопрос касается: производительности и читабельности, вы бы предпочли использовать следующее?

template <typename DST, typename... Ts>
void SetValue(DST& dst, Ts&&... ts)
{
  CheckAndSetVal(dst, std::forward<Ts>(ts)...);
}

template <typename DST>
void CheckAndSetVal(DST&) {}

template <typename DST, typename T1, typename T2, typename... Ts>
std::enable_if_t<std::is_same_v<DST, T2> > CheckAndSetVal(DST& dst, T1&& cond, T2&& val, Ts&&... ts)
{
  if (cond())
    dst = val; // Assign the value here ...
  else
    CheckAndSetVal(dst, std::forward<Ts>(ts)...);
}

template <typename DST, typename T1, typename T2, typename... Ts>
std::enable_if_t<!std::is_same_v<DST, T2> > CheckAndSetVal(DST& dst, T1&& cond, T2&& val, Ts&&... ts)
{
  if (cond())
    dst = val(); // Assign the value using this functor .. 
  else
    CheckAndSetVal(dst, std::forward<Ts>(ts)...);
}

  int i;
  //
  // In practive though the conditions are not as trivial as they look here. 
  //
  SetValue(i, []() { return false; }, 444
            , []() { return false; }, 999
            , []() { return true; }, []() { return 222; });

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Честно говоря, я бы предпочел оператор if-else или оператор ?:.Проще отлаживать или интерпретировать аварийные дампы.Легче читать не-C ++ разработчик или начинающий разработчик.И никаких серьезных недостатков.

0 голосов
/ 24 января 2019

Если удобочитаемость этой функции вызывает беспокойство, вы всегда можете избавиться от магии SFINAE, используя C ++ 17:)

#include <functional>
#include <type_traits>

template<class DestT, class CondT, class ValueT, class... Ts>
void SetValue(DestT& out, CondT&& cond, ValueT&& value, Ts&&... ts)
{
    if (cond())
    {
        if constexpr (std::is_invocable_v<ValueT>)
        {
            out = value();
        }
        else
        {
            out = value;
        }
    }
    else
    {
        if constexpr (sizeof...(Ts) != 0)
        {
            SetValue(out, std::forward<Ts>(ts)...);
        }
    }
}

int main()
{
    int i;
    SetValue(i, []() { return false; }, 444,
                []() { return false; }, 999,
                []() { return true; }, []() { return 222; });

    return i;
}

Производительность должна быть одинаковой для сборок релизов ивероятно, немного медленнее на неоптимизированных сборках.Например, приведенный выше код компилируется до return 222 в gcc / clang с оптимизацией.Время компиляции может занять немного больше времени, однако.

Я не фанат таких гигантских вариационных вызовов функций, как это, но иногда они того стоят, когда они экономят много типизации по всей базе кода.Трудно сказать, не зная вашего реального варианта использования.

...