2

我有一个专有的 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 还没有优化?

4

1 回答 1

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

显然你可以使更通用。

于 2013-02-02T10:03:48.167 回答