在 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_statement
是 true
或 false
是 TYPE_A
或 TYPE_B
。
之后,无论如何,我都会调用一个可以接受两种类型作为输入的重载函数doStuff()
。
备注:
getRef<TYPE_A>()
和 getRef<TYPE_B>()
对不同的数据进行操作并且几乎不相关
some_boolean_statement
是运行时间
现在,我不喜欢在 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>());
}
我看不出还有什么比这更好的了。此外,如果这是您代码中最大的问题,那么您的代码状态良好。
反转控制流和运行时以编译时间调度程序。
这在 c++11, and modestly complex in c++14 中非常复杂。
在c++14你可以得到:
pick( some_boolean_statement,
&getRef<TYPE_A>,
&getRef<TYPE_B>
)([&](auto* getRef){
const auto& ref = getRef();
doStuff(ref);
});
但基本上每一步都是 c++11 的痛苦。
另一种方法是制作一个存储指向 TYPE_A
或 TYPE_B
的指针的 std (c++17) or boost (c++03) 变体。然后使用 visit
;但即使在这里,您也需要一个自动 lambda 来保持您的代码简短。
最简单的c++14版本是:
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);
}
所以,我有以下代码:
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
是运行时间
现在,我不喜欢在 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>());
}
我看不出还有什么比这更好的了。此外,如果这是您代码中最大的问题,那么您的代码状态良好。
反转控制流和运行时以编译时间调度程序。
这在 c++11, and modestly complex in c++14 中非常复杂。
在c++14你可以得到:
pick( some_boolean_statement,
&getRef<TYPE_A>,
&getRef<TYPE_B>
)([&](auto* getRef){
const auto& ref = getRef();
doStuff(ref);
});
但基本上每一步都是 c++11 的痛苦。
另一种方法是制作一个存储指向 TYPE_A
或 TYPE_B
的指针的 std (c++17) or boost (c++03) 变体。然后使用 visit
;但即使在这里,您也需要一个自动 lambda 来保持您的代码简短。
最简单的c++14版本是:
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);
}