c++ - 如何防止手动实例化所有模板类型?
问题描述
我有一个函数Foo
可以获取两个模板参数L3HdrType
和L4HdrType
. 我收到一个数据包并解析它,然后需要调用该函数。我的代码目前看起来像:
ParsedPacket parsed_packet = parser.Parse(packet);
if (parsed_packet.ip_version() == IPv4 && parsed_packet.ip_proto() == TCP)
Foo(parsed_packet.L3Header<ipv4_hdr>(), parsed_packet.L4Header<tcp_hdr>());
if (parsed_packet.ip_version() == IPv6 && parsed_packet.ip_proto() == TCP)
Foo(parsed_packet.L3Header<ipv6_hdr>(), parsed_packet.L4Header<tcp_hdr>());
if (parsed_packet.ip_version() == IPv4 && parsed_packet.ip_proto() == UDP)
Foo(parsed_packet.L3Header<ipv4_hdr>(), parsed_packet.L4Header<udp_hdr>());
if (parsed_packet.ip_version() == IPv6 && parsed_packet.ip_proto() == UDP)
Foo(parsed_packet.L3Header<ipv6_hdr>(), parsed_packet.L4Header<udp_hdr>());
我的问题是,有没有办法减少这种代码重复?类似于以下内容:
Foo<parsed_packet.GetL3HeaderType(), parsed_packet.GetL4HeaderType()>(...);
这显然不起作用,因为在编译时不知道给定数据包的标头类型。
重复的来源是两个不同的 if 语句正在检查IPv4
并将其映射到ipv4_hdr
. 如果我可以在代码中的一个位置指定IPv4
映射到ipv4_hdr
then 这将使代码随着选项的数量线性增长,而不是指数增长,因为我可以以某种方式编写:
if (parsed_packet.ip_version() == IPv4) {
using L3HeaderType = ipv4_hdr;
}
...
Foo<L3HeaderType, L4HeaderType>(...)
请注意,我的实际代码需要支持的不仅仅是 4 种情况,因此实际上的代码比这里的示例难看得多,因为 if 语句的数量随着标头的数量呈指数增长。
解决方案
如果继承和运行时多态不是一个选项,您可以通过执行一些涉及 lambdas 的杂技来解耦两个模板参数的推导:
template <typename T> struct foo {};
template <typename T> struct bar {};
// the function to be called
template <typename A, typename B>
void foobar( foo<A> f, bar<B> b) {}
// bind the first parameter
template <typename T>
auto make_foofoo (foo<T> f) {
return [f](auto bar){ foobar(f,bar); };
}
// select second type here
template <typename F>
void do_the_actual_call(F f, int y) {
if (y == 1) f(bar<int>{});
if (y == 2) f(bar<double>{});
}
int main() {
// the "conditions"
int x = 1;
int y = 2;
// select first type here
if (x == 1) {
auto foofoo = make_foofoo(foo<int>{});
do_the_actual_call(foofoo,y);
} else if (x == 2){
auto foofoo = make_foofoo(foo<double>{});
do_the_actual_call(foofoo,y);
}
}
它仍然是重复的代码,但它x + y
不再像x * y
.
推荐阅读
- ansible - 如何使用 Ansible 中的主机变量值更新角色的参数?
- android - Firebase 通知声音无法正常工作
- apache-spark - 在 Spark 中加入 Dataframe 性能
- python - 制作 Keras 模型时将数据拆分为训练、测试和评估
- android - Android 11 - 在外部存储上创建应用程序特定目录
- c++ - 将 nlohmann::basic_json<> 转换为 std::tuple c++
- angular - 在带有 Angular 的 Storybook 6 中使用 TailwindCss
- javascript - 带有西里尔 URI 的 Nuxt 完全静态生成的页面问题
- linux - 在 bash 脚本中更改进程标题/名称
- node.js - 当数据实际准备好进行流式传输时,如何获得通知?