C++学习笔记——auto/decltype 自动推导类型

Posted 火山上的企鹅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++学习笔记——auto/decltype 自动推导类型相关的知识,希望对你有一定的参考价值。


C++11 新增了一个工具,让编译器能够根据初始值的类型判断变量的类型:自动类型推导(auto/decltype)

● auto 初识

auto x = 0L;          // 自动推导为long
auto y = &x;          // 自动推导为long*
auto z &x;          // 自动推导为long* 

int max_len = 1024;  
auto ptr = (int*)(&max_len ); // 自动推导为int* 

auto  i = 0;          // 自动推导为int类型
auto  x = 1.0;        // 自动推导为double类型
auto  str = "hello";  // 自动推导为const char [6]类型

std::map<int, std::string> m = 1,"a", 2,"b";     // 自动推导不出来
auto  iter = m.begin();                  // 自动推导为map内部的迭代器类型
auto  f = bind1st(std::less<int>(), 2);  // 自动推导出类型,具体是啥不知道
auto err;                                // 错误,没有赋值表达式,不知道是什么类型

在类成员变量初始化的时候,目前的 C++ 标准不允许使用 auto 推导类型

class X final 
 
	auto a = 10;                          // 错误,类里不能使用auto推导类型;
 

记住两条简单的规则:

● auto 总是推导出“值类型”,绝不会是“引用”;

● auto 可以附加上 const、volatile、*、& 这样的类型修饰符,得到新的类型。

如下:

auto        x = 10L;    //  auto推导为long,  x是long

auto&       x1 = x;      // auto推导为long, x1是long&
auto*       x2 = &x;     // auto推导为long,x2是long*
const auto& x3 = x;      // auto推导为long,x3是const long&
auto        x4 = &x3;    // auto推导为const long*,x4是const long*

优点总结:
1、避免未初始化变量。因为 auto 必须初始化才能使用
2、使代码简洁
3、避免了对类型的“硬编码”,定义类型更加灵活

再补充:auto的对应类型不是使用new出来的变量,也不是static变量,auto变量在函数结束时即释放了,再次调用这个函数时,又重新定义了一个新的变量。

● auto 最佳实践

在 “range-based for” 中,不需要关心容器元素类型、迭代器返回值和首末位置,就能非常轻松地完成遍历操作:

void autoTest() 

    //① 遍历 + 写
    string s1 =  "123456";
    for (auto i : s1 )  //普通方式改变访问
        i ++;            //改变字符串的每个字符, 不会改变整个字符串 s2
        cout << i ;
    
    cout<<"," << s1 << endl; //s1的值是 123456

    //② 遍历 + 写 + 引用
    string s2 = "123456";
    for (auto& i : s1 )      //引用方式访问元素
        i ++;                 //改变字符串的每个字符, 使用引用会改变整个字符串 s1
        cout << i ;
    
    cout<<"," << s1 <<endl; //s2的值是 234567

    //③遍历 + 常引用(只读)"
    string s3 = "123456";
    for(const auto& i : s3)   // 常引用方式访问元素,避免拷贝代价
//        i ++;                //报错
        cout << i;             // 常引用不会改变元素的值
    
    cout<<"," << s3 <<endl; //s3的值是 123456
    

打印结果:

为了保证效率,最好使用 “const auto&” 常引用 或者 “auto&” 引用。

● decltype 初识

int x = 0;                 // 整型变量
decltype(x)     x1;        // 推导为int,x1是int
decltype(x)&    x2 = x;    // 推导为int,x2是int&,引用必须赋值
decltype(x)*    x3;        // 推导为int,x3是int*
decltype(&x)    x4;        // 推导为int*,x4是int*
decltype(&x)*   x5;        // 推导为int*,x5是int**
decltype(x2)    x6 = x2;   // 推导为int&,x6是int&,引用必须赋值

decltype 不仅能够推导出值类型,还能够推导出引用类型,也就是表达式的“原始类型”。

就是写起来略麻烦,初始化的时候,表达式要重复两次(左边的类型计算,右边的初始化),把简化代码的优势完全给抵消了,所以一般情况使用 auto 。

● decltype 最佳实践:

当你感觉“这里我需要一个特殊类型”的时候,选 decltype 就对了。

比如说,定义函数指针在 C++ 里一直是个比较头疼的问题,因为传统的写法实在是太怪异了。但现在就简单了,你只要手里有一个函数,就可以用 decltype 很容易得到指针类型。

// UNIX信号函数的原型,看着就让人晕,你能手写出函数指针吗?
void (*signal(int signo, void (*func)(int)))(int)

// 使用decltype可以轻松得到函数指针类型
using sig_func_ptr_t = decltype(&signal) ;

另外一个是在类中使用,因为 auto 不能在定义类的时候使用:

class DemoClass final

public:
    using set_type      = std::set<int>;  // 集合类型别名
private:
    set_type      m_set;                   // 使用别名定义成员变量

    // 使用decltype计算表达式的类型,定义别名
    using iter_type = decltype(m_set.begin());

    iter_type     m_pos;                   // 类型别名定义成员变量
;

● 学习的课程和书籍:

《罗剑锋的 C++ 实战笔记》

《C++ Primer Plus 第六版》

以上是关于C++学习笔记——auto/decltype 自动推导类型的主要内容,如果未能解决你的问题,请参考以下文章

C++学习笔记——auto/decltype 自动推导类型

C++学习笔记——auto/decltype 自动推导类型

C++11新特性:3—— C++ decltype类型推导完全攻略

C++11新特性:3—— C++ decltype类型推导完全攻略

现代C++ 类型推导

C++11学习记录:核心语言功能特性