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


类型萃取(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
void send(const BUILDER& builder);

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

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

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

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


类型选择

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

你可能感兴趣的:(C++11 模板元编程 - 类型萃取)