在Clang / LLVM中内联函数指针数组

时间:2013-02-02 07:23:51

标签: c++ llvm clang

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

1 个答案:

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

显然你可以做得更通用。