美文网首页
C++11 模板元编程 - 类型萃取

C++11 模板元编程 - 类型萃取

作者: MagicBowen | 来源:发表于2016-09-17 09:22 被阅读516次

    类型萃取(trait)的概念我们前面有介绍过。可以将trait看做是一种静态反射技术,通过trait我们可以自动提取出想要的代码元信息,避免让客户代码显示去提供这些信息,从而使得客户代码更加的简洁。

    在dates中,客户可使用FakeSystem定义一个fake系统,与SUT交互。FakeSystem拥有sendrecv接口,分别向SUT发送消息,以及从SUT接收消息。send的入参是一个原型为void(Msg&)的lambda函数,用于描述如何构造Msg消息。

    visitor.send([this](AccessReq& req)
            {
                req.capability = CAPABILITY;
            });
    

    由于一个FakeSystem可以发送多种msg,所以send接口无法确定lambda的具体类型,因此send的参数只能定义为泛型参数,它的原型为:

    template<typename BUILDER>
    void send(const BUILDER& builder);
    

    这样send就可以传入各种构造不同消息类型的lambda了,而且还可以调用原型一致的普通函数或者仿函数,客户使用起来非常简洁。

    现在我们来实现sendsend中需要创建一个消息,然后交给builder去构造。如下伪代码:

    template<typename BUILDER>
    void send(const BUILDER& builder)
    {
        Msg msg; // 这里Msg到底应该是什么类型?
        builder(msg);
        // ...
    }
    

    上面代码的问题在于,我们不知道Msg的类型!Msg的类型是由客户传入的不同builder决定的,例如visitor.send([this](AccessReq& req){...})中,Msg是AccessReq。换句话说,我们需要从传入的lambda表达式的类型中获取Msg的类型。

    模板元编程可以帮助我们解决这个问题。还记得我们前面介绍的TLP库中trait工具中的__lambda_para()吗?于是代码修改如下:

    template<typename BUILDER> 
    void send(const BUILDER& builder)
    {
        using Msg = __lambda_para(BUILDER, 0); // 获取BUILDER的参数列表中的第一个参数类型
        Msg msg;
        builder(msg);
        // ...
    }
    

    如上我们通过类型萃取,从客户传入的函数类型中取出了参数的类型,使得框架的接口保持了简洁和灵活性。


    类型选择

    返回 C++11模板元编程 - 目录

    相关文章

      网友评论

          本文标题:C++11 模板元编程 - 类型萃取

          本文链接:https://www.haomeiwen.com/subject/rigiettx.html