深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-1

由来

    c++11由来已久,VS2015完全支持C++11标准,对C++14的支持已经基本完成,并支持部分C++17标准。但是,工作中使用到的语法却还是以c++98/03为主,对新引入的语法知之胜少,之前也一直想做一些深入的了解,但一直苦于没有一个良好的切入点,自从阅读《深入应用c++11代码优化与工程级应用》后发现本书对于c++11的使用写得相当透彻且配合例子很好理解,但粗看一遍往往不能深入领会其中的精髓,遂写次笔记加强理解。

auto使用

    auto的使用可以说是我最先使用过的c++11特性了,没有之一(主要是容器的遍历用于标识迭代器变量)。

推导规则

    当时使用就如上所说的一个应用例子,也没有细究auto推导的规则。书中做了总结,摘录下:1.当不声明为指针或引用时,auto的推导结果和初始化表达式抛弃引用和cv限定符(const和volatile限定符的统称)后类型一致;2.当声明为指针或引用时,auto的推导结果将保持初始化表达式的cv属性。

auto的限制

1.auto不能用于函数参数: void func(auto a = 1) {} // error
2.auto不能用于非静态成员变量:
c++
struct Foo
{
auto var1_ = 0;// error
static const auto var2_ = 0; // OK
}

3.auto 无法定义数组,无法推导出模板参数:
c++
int main()
{
int arr[10] = {0};
auto aa = arr;
auto rr[10] = arr; // error auto 无法定义数组
Bar<int> bar;
Bar<auto> bb = bar; // error auto无法推导出模板参数
return 0;
}

auto应用

1.用于容器遍历时声明迭代器类型;
2.用于在模板中接收一个模板函数的返回值用于后续处理。
c++
template<clas A>
void func()
{
auto val = A::get();
//...
}

decltype使用

    对于decltype和auto这两个在应用上看着有些类似,有些情况下可以互换,auto主要根据变量的初始化表达式推到出边个两应该具有的类型,而若想要通过某个表达式得到类型,但不希望新变量和这个表达式具有同样的值,此时auto就不适用了。此外,对于一般的标记符表达式,decltype将精确地推到出表达式定义本身的类型,不会像auto那样在某些情况下舍弃掉引用和cv限定符。

decltype推导规则

    decltype推导规则大部分比较显而易见,但一些情况还需要特别注意。
以下列出推导规则:decltype(exp)

  1. exp是标识符、类访问表达式–>decltype(exp)和exp类型一致;
  2. exp是函数调用–>decltype(exp)和返回值一致(函数返回值为纯右值时,只有类类型可以携带cv限定符,此外则一般忽略cv限定);
  3. 其他情况,若exp是一个左值,则decltype(exp)是exp的左值引用,否则和exp类型一致。
        针对以上几点进行举例:
    针对2中忽略cv限定符的情况:
 const int func_cint(void);

int main()
{
    decltype(func_cint()) m = 0;
    return 0;
}

这里写图片描述

针对3中描述的则需要比较注意,常常由于一个括号导致完全不同的推导:

struct Foo { int x; };

int main()
{
    const Foo foo = Foo();
    decltype(foo.x) a = 0;
    decltype((foo.x)) b = a; // 特别注意和上面的比较

    int n = 0, m = 0;
    decltype(m + n) c = 0;
    decltype(m += n) d = c;

    return 0;
}

附上vs上运行时的显示,可以对照规则3进行理解:
这里写图片描述

decltype应用

    书中有一步一步引出这种方式的步骤及和c++98/03的实现比较,这里直接列出方案:

template<class ContainerT>
class Foo {
    decltype(ContainerT().begin()) it_;
public:
    void func(ConstinerT& container)
    {
        it_ = constiner.begin();
    }
    //...
}

auto与decltype结合使用

    这两者结合主要用于返回类型后置语法,具体与c++98/03的比较就不罗列了,两个里字就行理解使用:

template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u)
{
    return t + u;
}
int& foo(int& i);
float foo(float& f);

template <typename T>
auto add(T &val) -> decltype(foo(val))
{
    return foo(val);
}

模板别名

c++11中新添加的using别名,绝大部分和typedef相同,这里就举个不同的例子:

template <typename val>
using str_map_t = std::map<std::string, val>;
//...
str_map_t<int> map1;

模板默认模板参数

    c++11中函数模板也支持默认参数,这个在之前c++98/03是不支持的。
注意:如果想禁止参数自动推导,可以使用外敷模板,示例如下

template <typename T>
struct identity
{
    typedef T type;
};

template<typename T = int>
void func(typename identity<T>::type val, T = 0) //  禁用了val的自动推导
{
    //...
}

列表初始化

具体就不多说了,举几个例子就可以知道用法了:

int a = {1}; // 虽然使用了等号,但它仍是列表初始化,私有的拷贝构造并不会影响它。
int a1{1};
int *a = new int{123};
int *arr = new int[3]{1, 2, 3};

如果自定义支持任意长度初始化列表,则需要使用到std::initializer_list,例子如下:

class Foo
{
public:
    Foo(std::initializer_list<int>) {

    }
};

Foo fool{ 1, 2, 3, 4 };

基于范围的for循环

这个使用比较简单,但有几点需要注意:
1.for(auto n : arr) { //…} //注意这里的arr只会计算一次,即首次即算出循环的终止条件,如果在循环中修改容器长度则循环次数仍然不会改变。
2.for循环可以直接遍历数组:

int fibarray[] = {0, 1, 1, 2, 3, 5, 8, 13};
for (auto v : fibarray) {
    std::cout << v << std::endl;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值