【发布时间】:2022-01-23 17:28:59
【问题描述】:
如果此处的任何术语有误,我们深表歉意。我想要理解的是——C++20 中的模板元编程和 SFINAE/概念等技术可以在编译时计算和删除分支。我似乎找不到答案的是,这是否在运行时保持无分支和/或是否比 if-else 块更快地根据重载/特殊情况找到要调用的函数?
我正在考虑的应用程序是自动交易。假设从交易所收到一条新消息,它是一个“买入”订单。处理这个问题的一种方法是一个简单的 if-else 语句,它检查它是否是一个买单并运行相应的函数来处理一个买单消息。相反,到目前为止,我对替代解决方案的理解是,可以使用多个模板函数重载来决定调用哪个函数,其中所选函数是其模板参数/要求与传入类型/类最匹配或完全满足的函数.
下面的伪代码。
选项 1 - 分支 if 语句:
if (order.side == "buy") { /*handle buy message*/ }
else { /*handle sell message*/ }
选项 2 - 函数重载
template<class Order>
//some code (SFINAE/concepts/requires) that means this function will only be chosen if the class Order
//contains a member variable "buy" e.g. Order::buy is present or Order::buy = true;
void process_order() { /*handle buy message*/ }
template<class Order>
//some code (SFINAE/concepts/requires) that means this function will only be chosen if the class Order
//contains a member variable "sell" e.g. Order::sell is present or Order::sell = true;
void process_order() { /*handle sell message*/ }
我想知道的是,在运行时,选项 1 总是会产生一个分支。选项 2 是无分支的,但直观地感觉在运行时会产生一些开销,因为每次都必须搜索多个函数重载并找到最合适的,因为买卖订单是随机到达的。所以我的问题是 - 这种开销是否真的存在,或者有一个巧妙的技巧被使用/发生了一些不同的事情?如果它确实存在,它是否仍然比分支快?如果是,为什么 - 考虑到仍然必须使用某些逻辑来搜索适用的功能?是不是选项 2 在运行时更快/无分支,因为编译器可以根据出现的类硬连线将采用的路径,因此当该类呈现给程序时,它确切知道要加载哪组指令?任何见解将不胜感激:)
【问题讨论】:
-
选项 2 首先不起作用。重载解析和模板推导是纯粹的编译时概念。它们绝不会受到运行时值的影响。在生成的代码中,对所选重载始终只有一个函数调用。
-
如果你必须在运行时确定类型,你总会有一个分支/跳转。重载解析发生在编译时。
-
"考虑到仍然必须使用一些逻辑来搜索适用的功能?"正确的。无论您是否必须在运行时分支,都没有“魔法”(好吧,分支预测有点神奇,但那是在 cpu 级别)
-
模板、SFINAE 和概念是编译时概念。然而,这并不意味着他们可以神奇地将运行时分支转变为编译时分支。相反,当您可以在编译时做出决定时,您可以使用这些技术。
标签: c++ branch c++20 template-meta-programming sfinae