使用两个列表的组合生成函数调用

时间:2019-01-28 17:31:53

标签: c++ macros c++17

我想测试很多不同的消息类型,其中每种消息类型可以包含不同种类的对象。我有

template <typename ObjectT> class MessageRequest1;
template <typename ObjectT> class MessageReply1;
...
template <typename ObjectT> class MessageRequestN;
template <typename ObjectT> class MessageReplyN;

同样,我有很多对象类型。 我有可以测试类型组合的模板功能:

template <MessageType, ObjectType> bool TestFunction(void);

我想做的是有一个宏系统(或其他东西),它可以使用MessageTypes和ObjectTypes的所有组合调用我的TestFunction。我正在设想类似的东西:

ADD_MESSAGE_TYPE(1);
...
ADD_MESSAGE_TYPE(N);

ADD_OBJECT_TYPE(Object1);
...
ADD_OBJECT_TYPE(ObjectN);

将使用所有消息类型的所有对象类型生成对TestFunction的调用。关于如何实现这一目标的任何想法?

2 个答案:

答案 0 :(得分:2)

我的方法是将这些类型的列表存储在可变包装类中,然后使用折叠表达式为每种类型组合生成函数调用:

template<class ... Ts>
struct wrapper
{};

template<template<class> class ... Ts>
struct templateWrapper
{};


using ObjectTypes = wrapper<
    Object1,
    //...
    ObjectN
    >;

using MessageTypes = templateWrapper<
    MessageRequest1,
    MessageReply1,
    //...
    MessageRequestN,
    MessageReplyN
    >;

template<class MessageType, class ObjectType>
bool TestFunction(void);

template<template<class> class MessageType, class ... ObjectTypes>
bool callForAllYall_helper2(wrapper<ObjectTypes...>*)
{
    return (TestFunction<MessageType<ObjectTypes>, ObjectTypes>() && ...);
}

template<template<class> class ... MessageTypes>
bool callForAllYall_helper1(templateWrapper<MessageTypes...>*)
{
    return (callForAllYall_helper2<MessageTypes>((ObjectTypes*)(nullptr)) && ...);
}

bool callTestFunctionForAllYall()
{
    return callForAllYall_helper1((MessageTypes*)(nullptr));
}

https://godbolt.org/z/Cj6cDS

不需要宏!

检查生成的程序集,以确保确实对每对TestFunction<MessageType<ObjectType>, ObjectType>都调用MessageType, ObjectType。我and将返回值放在一起,因为这大概就是您想要的。您可以将&&替换为,,以舍弃(最后一个除外)所有值。

要进一步抽象并为不同的测试函数重用相同的代码实际上会有点困难,因为您不能将模板化函数作为模板参数(仅将其实例化,在此无济于事)。您必须将所有测试函数包装在可以作为类型参数传递(并传递给最内部的辅助函数)的结构(或lambda)中。

答案 1 :(得分:1)

由于某种原因,@ Max的answer并非零成本(生成testje指令)。以下是我的零成本c ++ 14版本。 https://gcc.godbolt.org/z/kwgMZK

#include <type_traits>

//User Objects
template<class Obj>
struct Msg1;
template<class Obj>
struct Msg2;
template<class Obj>
struct Msg3;

struct Obj1;
struct Obj2;
struct Obj3;
struct Obj4;

template<class MsgType, class ObjType>
void TestFunction(void);

namespace helper {
    template<template<class Obj> class Msg>
    struct TMsg {
        template<class O>
        using RMsg = Msg<O>;
    };

    template<class... Type>
    struct Wrap{};

    template<class Msg>
    void caller1(Msg, Wrap<>){}

    template<class Msg, class Obj, class... Objs>
    void caller1(Msg m, Wrap<Obj, Objs...> O) {
        Obj o;
        using TMsgL = typename std::remove_reference<decltype(*m)>::type;
        using ObjL = typename std::remove_reference<decltype(*o)>::type;
        using MsgL = typename TMsgL::template RMsg<ObjL>;
        TestFunction<MsgL, ObjL>();
        Wrap<Objs...> r;
        caller1(m, r);
    }

    template<class... Objs>
    void caller(Wrap<>, Wrap<Objs...>){}

    template<class Msg, class... Msgs, class... Objs>
    void caller(Wrap<Msg, Msgs...> M, Wrap<Objs...> O){
        Msg m;
        caller1(m, O);
        Wrap<Msgs...> ML;
        caller(ML, O);
    }
}

void foo(){
    using Msgs = helper::Wrap<helper::TMsg<Msg1>*, helper::TMsg<Msg2>*, helper::TMsg<Msg3>*>;
    using Objs = helper::Wrap<Obj1*, Obj2*, Obj3*, Obj4*>;
    Msgs m;
    Objs o;
    caller(m, o);
}

生成的程序集

foo():
        sub     rsp, 8
        call    void TestFunction<Msg1<Obj1>, Obj1>()
        call    void TestFunction<Msg1<Obj2>, Obj2>()
        call    void TestFunction<Msg1<Obj3>, Obj3>()
        call    void TestFunction<Msg1<Obj4>, Obj4>()
        call    void TestFunction<Msg2<Obj1>, Obj1>()
        call    void TestFunction<Msg2<Obj2>, Obj2>()
        call    void TestFunction<Msg2<Obj3>, Obj3>()
        call    void TestFunction<Msg2<Obj4>, Obj4>()
        call    void TestFunction<Msg3<Obj1>, Obj1>()
        call    void TestFunction<Msg3<Obj2>, Obj2>()
        call    void TestFunction<Msg3<Obj3>, Obj3>()
        add     rsp, 8
        jmp     void TestFunction<Msg3<Obj4>, Obj4>()