【问题标题】:Generate function calls using combinations from two lists使用来自两个列表的组合生成函数调用
【发布时间】:2019-01-28 17:31:52
【问题描述】:

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

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 的调用,其中包含所有消息类型的所有对象类型。关于如何实现这一点的任何想法?

【问题讨论】:

  • MessageRequestN/MessageReplyN 是否与MessageType 模板参数相关?或者为什么它们对这个问题很重要?
  • 你的意思是template&lt;template&lt;class&gt;class MessageType, class ObjectType&gt; bool TestFunction(void); 吗?

标签: c++ macros c++17


【解决方案1】:

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

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

不需要宏!

检查生成的程序集以验证这确实为每对MessageType, ObjectType 调用TestFunction&lt;MessageType&lt;ObjectType&gt;, ObjectType&gt;。我anded 将返回值放在一起,因为这可能是您想要的。您可以将 &amp;&amp; 替换为 , 以丢弃(除最后一个之外的所有)值。

进一步抽象并为不同的测试函数重用相同的代码实际上有点困难,因为您不能将模板化函数作为模板参数传递(只有它们的实例化,这在这里没有帮助)。您必须将所有测试函数包装在可以作为类型参数传递的结构(或 lambda)中(并将其传递给最里面的辅助函数)。

【讨论】:

    【解决方案2】:

    由于某种原因@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>()
    

    【讨论】:

    • 我的版本不是零成本,因为我不只是丢弃所有返回值。这里的假设是 bool 返回值有一些用处(比如“测试是否成功”)。正如我所说,将我的答案中的&amp;&amp; 替换为,becomes "zero cost"。不过,您的回答很有帮助,因为它是 C++ 14。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    相关资源
    最近更新 更多