2.auto

上一个条款也有谈到auto,auto看起来很简单,但是还是有些情况需要注意。这里主要讲如何去引导auto得出正确的结果

条款05:优先选用auto,而非显示型别声明

这个条款给出几个理由,让我们优先选择使用auto。下面几个例子可以展示

int x;      //忘记初始化

template<typename It>
void dwim(It a,It b){
    while(a!=b){
        typename std::iterator_traits<It>::value_type
            currValue = *b;         //定义又臭又长
    }
}

auto x=5;   //必须初始化

template<typename It>
void dwim(It a,It b){
    while(a!=b){
        auto currValue = *b;         //只需要auto即可
    }
}

//一般是有lambda的时候都是用auto,不然你拿捏不了型别

auto func=[](int a,int b){return a==b;};
auto func_auto=[](auto a,auto b){return a==b;};

//不用auto也是可以声明lambda表达式的,可以用std::function,但是会啰嗦,以及占用更多的内存。

function<bool(const std::unique_ptr<Widget>&,
                const std::unique_ptr<Widget>&)>
        dereFUPLess = [](const std::unique_ptr<Widget>&p1,
                const std::unique_ptr<Widget>&p2){return *pa<*p2;};
//可以看到,上面的声明巨麻烦,并且std::function会占用更多的内存

上面主要讲的是auto的便利,下面一个例子能体现使用auto的更大的好处。

std::unordered_map<std::string,int> ma;

for(const std::pair<std::string,int>&p:ma){
    //do something
}

可以看到,大家应该都觉得这里没啥问题。但是map的key是默认const的。也就是这里真实的构造其实是 const std::pait,这里不匹配,要执行编译器强制转换。将所有的key复制一遍。开销巨大。可能有时候你写出这种代码,自己都不知道哪里出了问题。使用auto的话,这里什么问题都不会存在了。

当使用auto推导的型别不符合要求的时候,使用带显式型别的初始化物习惯用法

有些方法返回的不是你所想的结果。因为有些类被设计为代理类,返回值可以隐式转换到你认为的结果。但是使用auto却不可以,auto会为你推导出本来的结果。vector< bool >中operator[]就是一个典型的例子,他返回值不是bool&,如果用auto接收,就会出乎你的意料。使用上一节末尾的编译器识别类型,得出vector< bool >中operator[]返回的结果类型为

可以看到,类型是std::_Bit_reference&,这个类型我相信大家应该都没用过。

这个条款说的就是,有的时候还是使用显式声明比较好。但这不是说不用auto,还是建议使用auto,因为这种情况不多。

Last updated

Was this helpful?