Хороший способ организовать код, включающий константные ссылки с ограниченной областью действия и шаблоны в C ++ - PullRequest
0 голосов
/ 05 мая 2018

Итак, у меня есть следующий фрагмент кода:

if (some_boolean_statement)
{
    const auto& ref = getRef<TYPE_A>(); //getRef returns TYPE_A
    doStuff(ref);
}
else
{
    const auto& ref = getRef<TYPE_B>(); //getRef returns TYPE_B
    doStuff(ref);
}

Итак, я хочу получить постоянную ссылку ref, которая в зависимости от того, является ли some_boolean_statement true или false либо TYPE_A, либо TYPE_B. После этого, несмотря ни на что, я назову перегруженную функцию doStuff(), которая может принимать оба типа в качестве ввода.

Примечания:

  • getRef<TYPE_A>() и getRef<TYPE_B>() работают с разными данными и в значительной степени не связаны
  • some_boolean_statement - время выполнения

Теперь мне не нравится, что я должен написать doStuff(ref); в обеих ветвях оператора if. Но поскольку область действия ref ограничена, я не вижу четкого способа сделать это.

Я что-то упускаю очень просто? Любой совет?

Ответы [ 3 ]

0 голосов
/ 05 мая 2018

Инвертировать поток управления и время выполнения для компилятора времени компиляции.

Это безумно сложно в и скромно сложно в .

В вы можете получить:

pick( some_boolean_statement,
  &getRef<TYPE_A>,
  &getRef<TYPE_B>
)([&](auto* getRef){
  const auto& ref = getRef();
  doStuff(ref);
});

но в основном каждый шаг на этом пути - боль в .

Другой подход заключается в создании варианта std () или boost (), в котором хранится указатель на TYPE_A или TYPE_B , Затем используйте visit; но даже здесь вам понадобится автоматическая лямбда, чтобы ваш код был коротким.

Самая простая версия:

auto doWork = [&](const auto& ref) {
  doStuff(ref);
};
if (some_boolean_statement) {
  doWork(getRef<TYPE_A>());
} else {
  doWork(getRef<TYPE_B>());
}
0 голосов
/ 05 мая 2018

Можно написать класс диспетчера типа коммутатора, который отображает значение условия на целевой тип и допускает действие, которое будет выполнено только один раз, поэтому использование будет примерно таким:

 Switch<Action, bool, Case<true, TYPE_A>, Case<false, TYPE_B>>(some_boolean_statement);

Реализация концепции:

#include <iostream>
#include <cstdlib>

template<auto cond, typename x_Target> struct
Case;

template<template<typename T> class x_Action, typename x_Cond, typename... x_Case>
class DispatchImpl;

template<template<typename T> class x_Action, typename x_Cond, x_Cond this_cond, typename x_Target, typename... x_Case>
class DispatchImpl<x_Action, x_Cond, Case<this_cond, x_Target>, x_Case...>
{
    public: static void Dispatch(x_Cond cond)
    {
        if(this_cond == cond)
        {
            x_Action<x_Target>::Invoke();
        }
        else
        {
            DispatchImpl<x_Action, x_Cond, x_Case...>::Dispatch(cond);
        }
    }
};

template<template<typename T> class x_Action, typename x_Cond>
class DispatchImpl<x_Action, x_Cond>
{
    public: static void Dispatch(x_Cond) {}
};

template<template<typename T> class x_Action, typename x_Cond, typename... x_Case>
void Switch(x_Cond cond)
{
    DispatchImpl<x_Action, x_Cond, x_Case...>::Dispatch(cond);
}

//
template<typename T> auto getRef(void) { return T{}; }
void doStuff(int) { ::std::cout << "int" << ::std::endl; }
void doStuff(float) { ::std::cout << "float" << ::std::endl; }

template<typename x_Target> struct
Action
{
    static void Invoke(void)
    {
        doStuff(getRef<x_Target>());
    } 
};

int main()
{
   auto cond{false};
   Switch<Action, bool, Case<true, int>, Case<false, float>>(cond);
}

онлайн-компилятор

0 голосов
/ 05 мая 2018

Поскольку some_boolean_statement оценивается во время выполнения, нельзя избежать части кода if-else.

Наименьшее количество кода, которое вы должны иметь в каждой ветви оператора if, составляет один оператор. Лучшее, что вы можете сделать, - это написать другие функции или шаблоны функций, чтобы минимизировать объем кода в двух ветвях.

Вы можете использовать

if (some_boolean_statement)
{
   doStuff<TYPE_A>();
}
else
{
   doStuff<TYPE_B>();
}

, где

template <typename T> void doStuff()
{
   doStuff(getRef<T>());
}

Я не понимаю, как вы можете добиться большего, чем это. Кроме того, если это самая большая проблема в вашем коде, ваш код имеет хорошую форму.

...