在 C++ 中组织涉及具有有限范围和模板的 const 引用的代码的好方法

A good way to organize a code involving const references with limited scope and templates in C++

所以,我有以下代码:

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_statementtruefalseTYPE_ATYPE_B。 之后,无论如何,我都会调用一个可以接受两种类型作为输入的重载函数doStuff()

备注:

现在,我不喜欢在 if 语句的两个分支中都必须写 doStuff(ref);。但是由于 ref 的范围有限,我没有看到一个明确的方法。

我是不是漏掉了一些非常简单的东西?有什么建议吗?

由于 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>());
}

我看不出还有什么比这更好的了。此外,如果这是您代码中最大的问题,那么您的代码状态良好。

反转控制流和运行时以编译时间调度程序。

这在 , and modestly complex in 中非常复杂。

你可以得到:

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

但基本上每一步都是 的痛苦。

另一种方法是制作一个存储指向 TYPE_ATYPE_B 的指针的 std () or boost () 变体。然后使用 visit;但即使在这里,您也需要一个自动 lambda 来保持您的代码简短。

最简单的版本是:

auto doWork = [&](const auto& ref) {
  doStuff(ref);
};
if (some_boolean_statement) {
  doWork(getRef<TYPE_A>());
} else {
  doWork(getRef<TYPE_B>());
}

可以编写类似开关的调度程序 class 将条件值映射到目标类型并接受只执行一次的操作,因此用法类似于:

 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);
}

online compiler