《Effective Modern C++》学习笔记之条款三十三:对auto&&型别的形参使用decltype,以std::forward之

泛型lambda式(generic lambda)是C++14最振奋人心的特征之一,lambda可以在形参规格中使用auto。这个特性的实现十分直接了当:闭包类中的operator()采用模板实现。例如,给定下述lambda式:

auto f = [](auto x) { return func(normalize(x));};

以上语句翻译的闭包类代码如下:

class SomeComilerGeneratedClassName {
public:
    template<typename T>                //auto型别的返回值
    auto operator()(T x) const          //参见Item 3
    {  return func(normalize(x));}
    ...
};                                      //闭包类的其他功能

在本例中,lambda式对x实施的唯一动作就是将其转发给normalize。但是如果normalize区别对待左值和右值,那么该lambda式撰写的是有问题的,因为在此lambda总会传递左值(形参x)给normalize,即使传递给lambda式的实参是个右值。

该lambda式的正确撰写方式是把x完美转发给normalize,这就要求代码中修改两处,首先,x要改成万能引用(参见Item 24);其次,使用std::forward(参见Item 25)把x转发给normalize。概念上不难理解,这两处的修改都是举手之劳:

auto f = [](auto&& x){ return func(normalize(std::forward<???>(x)));};

可是问题就出在,上面代码里面的???应该怎么办呢?

通常情况下,在使用完美转发的时候,你是在一个接受型别形参T的模板函数中,所以,你写std::forward<T>就好。但是在泛型lambda式中,却没有可用的型别形参T。在lambda式生成的闭包内的模板化operator()函数中的确有个T,但是在lambda式中无法指涉,所以也没用。

前面我们已经说过,如果把实参左值传递给万能引用型别的形参,则该形参的型别会被推导为左值引用,如果传递是右值,则该形参会成为右值引用。那这也就意味着我们可以在该lambda表达式中探查x的型别,判断传入的实参是左值还是右值。而decltype则可以完成探查工作,如果传入的是个左值,decltype(x)将会产生左值引用型别,如果传入的是个右值,decltype(x)将会产生右值引用。

我们还知道,使用std::forward时惯例是:用型别形参为左值引用表明想要返回左值,而用非引用型别时来表达想要返回的右值。

再看看我们的lambda式,如果x绑定了左值,decltype(x)将产生左值引用型别。这符合惯例。不过,如果x绑定的是个右值,decltype(x)将会产生右值引用惯例,并非惯例的右值。

但是这里需要说明的是,在使用std::forward时,使用一个右值引用型别和使用一个非引用型别,会产生相同结果。所以如果x绑定的是个右值,decltype(x)后的std::forward()依然符合惯例。

示例代码如下:

//单一变量
auto f = 
    [](auto&& param)
    {
        return func(normalizer(std::forward<decltype(param)>(param)));
    }
//多变量

auto f = 
    [](auto&&... param)
    {
        return func(normalizer(std::forward<decltype(param)>(param)...));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiang木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值