我有一个专有的MCU执行定期任务,并希望用其他事情来填补“停机时间”。通常情况下,这是通过大型switch语句完成的,这是可以的,但我想知道是否有更优雅的方式。这是这个特定设备的代码中非常常见的模式,因此使用通用方法会很好。
所以我编写了以下代码,它可以工作,但它目前没有内联函数。
static InterlacedFunction searchFunctions[4] = {...};
typedef int (* const InterlacedFunction)(int);
template<const int numberOfWovenFunctions> int SendPacketWithWovenFunctions(
int * packet,
const int packetLength,
InterlacedFunction (&functions)[numberOfWovenFunctions],
int firstArgument = 0)
{
int returnFromLastWoven = (numberOfWovenFunctions != 0) ? (functions[0])(firstArgument) : 0;
SendData(packet[0]);
for(int i = 1; i < packetLength; i++)
{
if(i < numberOfWovenFunctions)
returnFromLastWoven = (functions[i])(returnFromLastWoven);
SendData(packet[i]);
}
return returnFromLastWoven;
}
我错过了什么,Clang不可能内联这些功能,还是Clang还没有进行优化呢?
答案 0 :(得分:2)
一般情况下,编译器在通过函数指针内联调用时并不积极,即使它们在编译时已知。
在这种情况下,您依靠编译器足够聪明地将循环展开到numberOfWovenFunctions迭代块中,或者为您生成内联函数的切换,这两者都不太可能。
如果你想让这个成语更通用你可以使用递归模板(如果你没有c ++ 11可变参数模板那么写会很难),尽管它是否真的构成了一个简化也许是有问题的。
即。您在编织函数指针值列表上的模板,并在每个级别调用编织函数,存储结果,调用sendPacket和递归到存储结果的下一个模板级别。像(未经测试)的东西:
template <InterlacedFunction ... args>
struct WovenFunc;
//Base case - send remaining packets
template <>
struct WovenFunc<>{
static int call(int value, int * packet, size_t count){
for(size_t c = 0; c < count; ++c) SendData(packet[c]);
return value;
}
};
//Recursive case - send packets + weave functions
template <InterlacedFunction arg, InterlacedFunction ... args>
struct WovenFunc<arg, args...>{
static int call(int initial, int * packets, size_t count){
int r = arg(initial);
SendData(packets[0]);
if(count)
return WovenFunc<args...>::call(r, packets + 1, count - 1);
}
};
然后在发送:
typedef WovenFunc<Woven1, Woven2, Woven3> WovenSend
WovenSend::call(returnFromLastWoven, packets, packetLength);
显然你可以做得更通用。