当前位置: 首页 > news >正文

C++学习:C++11关于类型的处理

        之前我们已经学习了对于C++类型处理的相关知识。作为一个以类型安全为宗旨的语言,对于数据类型的认识是十分重要的。本期我们就来学习一下C++11中更好用的类型表达及其对数据类型的处理。

        作者的个人gitee:https://gitee.com/riko-lou-tian/cpp-code-learning

        喜欢请支持一下谢谢

目录

auto

decltype

尾置返回类型

        基本语法

        为什么需要尾置返回类型

        使用场景

typedef和using


auto

        前⾯课程中我们已经⽤过auto,auto是⼀个类型说明符,他让编译器替我们分析表达式的类型,auto x = y + z; 编译器⾃动根据y+z相加的结果来推导x的类型,在⼀些类型⽐较⻓的场景,如前⾯讲的迭代器遍历时⾮常有⽤。

        编译器推导auto类型时,有时候也会和初始值的类型不⼀样,编译器会适当的改变结果类型,使其更符合初始化规则。⾸先使⽤引⽤其实是使⽤引⽤的对象,特别是当引⽤被⽤作初始值时,真正参与初始化的其实是引⽤对象的值,所以编译器推导auto为引⽤对象的类型,⽽不是引⽤。其次⼀个带有const属性的值初始化auto对象推导时忽略掉顶层const,保留底层const

        auto不能⾃动推导出引⽤类型,所以我们如果想将auto推导为引⽤类型,需要明确的指出:

auto& x = i;

        auto不能推导出顶层const,如果想使⽤auto推导出顶层const,需要明确的指出:

const auto x = ci;

        设置⼀个类型为auto引⽤时,初始值中的顶层const属性仍然保留,否则存在权限放⼤问题。

#include <iostream>using namespace std;
int main()
{int i = 0;int& ri = i;const int ci = 42; // 顶层constint* const p1 = &i; // 顶层constconst int* p2 = &ci; // 底层constconst int& ri1 = ci; // 底层constconst int& ri2 = i; // 底层constauto j = ri; // j类型为intj++;auto k = i; // k类型为intk++;auto r1 = ci; // r1类型为int,忽略掉顶层constr1++;auto r2 = p1; // r2类型为int*,忽略掉顶层constr2++;auto r3 = p2; // r3类型为const int*,保留底层const// (*r3)++; // 报错auto r4 = ri1; // r4类型为int,因为ri1是ci的别名,ci本⾝的const是⼀个顶层const被忽略掉了r4++;auto r5 = ri2; // r5类型为intr5++;const auto r7 = ci; // r7类型为const intauto& r8 = ri1; // r8类型为const int&auto& r9 = ri2; // r9类型为const int&auto& r10 = ci; // r10类型为const int&auto& r11 = ri; // r11类型为int&//r7++; // 报错//r8++; // 报错//r9++; // 报错//r10++; // 报错r11++;return 0;
}

        auto& 声明⼀个左值引⽤,它只能绑定到左值,如果初始化对象有const属性,推导时会保持

const 限定符,否则涉及权限放⼤。

        const auto& 声明⼀个const 左值引⽤,既可以绑定到左值⼜可以绑定到右值,不会修改绑定

对象。

        auto&& 是万能引⽤,遵循引⽤折叠的规则,既可以绑定到左值⼜可以绑定到右值,初始化表达式⾃动推导为左值引⽤或右值引⽤,如果初始化对象有const属性,推导时会保持 const 限定符。

        注意:auto不可以定义成员变量!

        测试代码:

#include <iostream>
#include<vector>
using namespace std;void func(int& x)
{cout << "void func(int& x)" << endl;
} 
void func(int&& x)
{cout << "void func(int&& x)" << endl;
} 
void func(const int& x)
{cout << "void func(const int& x)" << endl;} 
void func(const int&& x)
{cout << "void func(const int&& x)" << endl;
} 
int main()
{int x = 10;const int cx = 20;auto& rx1 = x; // int&auto& rx2 = cx; // const int&func(rx1);func(rx2);const auto& rx3 = x; // const int&const auto& rx4 = cx; // const int&func(rx3);func(rx4);// 万能引⽤auto&& rx5 = x; // int&auto&& rx6 = cx; // const int&func(rx5);func(rx6);auto&& rx7 = move(x); // int&&//rx7++;auto&& rx8 = move(cx); // const int&&//rx8++;func(forward<int>(rx7));func(forward<const int>(rx8));return 0;
}

        结果为:

decltype

        如果我们希望⽤表达式推出变量的类型,但是不想⽤表达式的值初始化变量,那么这时可以使⽤decltype。

 decltype(f()) x;

        需要注意的是编译器并不会实际调⽤f函数,⽽是⽤f的返回类型作为x的类型。

        decltype 处理const和引⽤的⽅式和auto也有所不同,

 decltype(const变量表达式) x 

        x的类型推出类型为const T,decltype会保留顶层const; decltype(引⽤变量表达式) x ,x的

类型推出类型为T &,decltype会保留引⽤;要注意这⾥跟auto是完全不同的。

        decltype还有⼀些特殊处理⽐较奇怪,

decltype(*p) x;

        x的类型是T&,decltye推导解引⽤表达式时,推出类型是引⽤;

 decltype((i)) x;

x的类型是T&,decltye推导解括号括起来的左值表达式时,推出类型是引⽤;

#include <iostream>
using namespace std;
int main()
{int i = 0;const int ci = 0;const int& rci = ci;decltype(i) m = 1; // m的类型是intdecltype(ci) x = 1; // x的类型是const intm++;x++; // 报错decltype(rci) y = x; // y的类型是const int&y++; // 报错decltype(rci) z; // 报错int* p1 = &i;decltype(p1) p2 = nullptr; // p2的类型是int*// 特殊处理decltype(*p1) r1 = i; // r1的类型是int&,解引⽤表达式推导出的内容是引⽤decltype(i) r2;// r3的类型是int&, (i)是⼀个表达式,变量是⼀种可以赋值特殊表达式,// 所以会推出引⽤类型decltype((i)) r3 = i; return 0;
}

        auto必须要通过初始化值推导类型,像类的成员变量这种就没办法使⽤auto,decltype可以很好的解决这样的问题

#include <iostream>
#include<vector>
using namespace std;
template <typename T>
class A
{public :void func(T& container){_it = container.begin();}
private:// 这⾥不确定是iterator还是const_iterator,也不能使⽤auto//typename T::iterator _it;// 使⽤decltype推导就可以很好的解决问题decltype(T().begin()) _it;
};
int main()
{const vector<int> v1;A<const vector<int>> obj1;obj1.func(v1);vector<int> v2;A<vector<int>> obj2;obj2.func(v2);return 0;
}

        decltype可以用来实例化lambda表达式的类型进行赋值

int main()
{//decltype在lambda表达式中也能用的应用auto lambda1 = [](int x, int y) { return x + y; };decltype(lambda1) lambda2 = lambda1;  // 复制构造// 使用std::cout << lambda1(5, 3) << std::endl;  // 8std::cout << lambda2(5, 3) << std::endl;  // 8return 0;
}

        decltype还可以⽤来解决函数尾置返回类型的问题,有时⼀个函数模板的类型跟是不确定的,跟某个参数对象有关,需要进⾏推导,直接⽤decltype推导去做返回类型是不⾏了,因为C++是前置语法,往前找不到这个推导对象,这个对象在参数⾥⾯,所以auto做返回值,然后->decltype(对象)做尾置推导

template<class R, class Iter>
R Func(Iter it1, Iter it2)
{R x = *it1;++it1;while (it1 != it2){x += *it1;++it1;} return x;
} 
// 不⽀持这样写,因为C++是前置语法,编译器遇到对象只会向前搜索
//template<class Iter>
//decltype(*it1) Func(Iter it1, Iter it2)
//{
// auto& x = *it1;
// ++it1;
// while (it1 != it2)
// {
// x += *it1;
// ++it1;
// }
// return x;
//}
// 返回位置⽤auto,函数后⾯接->推导返回类型的位置返回值⽅式
// 要注意decltype(*it1)推导出的是引⽤类型
//template<class Iter>
//auto Func(Iter it1, Iter it2)->decltype(*it1)
//{
// auto& x = *it1;
// ++it1;
// while (it1 != it2)
// {
// x += *it1
// ++it1;
// }
// return x;
//}
int main()
{vector<int> v = { 1,2,3 };list<string> lt = { "111","222","333" };// 这⾥⽆法调⽤上⾯的函数,因为函数模板只能通过实参推导模板类型,⽆法推导R//auto ret1 = Func(v.begin(), v.end());//auto ret2 = Func(lt.begin(), lt.end());// 显⽰实例化能解决问题,但是调⽤就很⿇烦auto ret1 = Func<decltype(*v.begin())>(v.begin(), v.end());auto ret2 = Func<decltype(*lt.begin())>(lt.begin(), lt.end());cout << ret1 << endl;cout << ret2 << endl;return 0;
}

        decltype(auto) 是 C++14 引⼊的特性,它结合了 auto 的便利性和 decltype 的精确类型推导能⼒。

//decltype(auto) 
int main()
{int i = 0;int& ri = i;const int ci = 42; // 顶层constint* const p1 = &i; // 顶层constconst int* p2 = &ci; // 底层constauto j = ri; // j类型为intdecltype(auto) j1 = ri; // j1类型为int&++j1;auto r1 = ci; // r1类型为int,忽略掉顶层constdecltype(auto) rr1 = ci; // rr1类型为const intr1++;//rr1++;auto r2 = p1; // r2类型为int*,忽略掉顶层constdecltype(auto) rr2 = p1; // rr1类型为int* constr2++;//rr2++;auto r3 = p2; // r3类型为const int*,保留底层constdecltype(auto) rr3 = p2; // rr3类型为const int*// (*rr3)++;return 0;
}

尾置返回类型

        尾置返回类型是C++11引⼊的⼀种函数声明语法,它允许将函数的返回类型放在参数列表之后⽽不是函数名前。尾置返回类型的语法这⾥我们简单的做个了解即可,因为C++14引⽤了auto做返回类型时,返回类型⾃动推导,很多地⽅就不太需要尾置返回类型了
        

        基本语法

auto functionName(parameters) -> returnType 
{// 函数体
}

        为什么需要尾置返回类型

        1. 提⾼代码可读性:特别是当返回类型很⻓或复杂时

        2. ⽀持Lambda表达式:Lambda表达式的返回类型必须使⽤尾置语法

        3. 模板编程:在模板函数中,返回类型可能依赖于参数类型

        使用场景
 

// 1. 复杂返回类型
auto getComplexType() -> std::map<std::string, std::vector<int>> {// ...
}
// 2. 依赖参数类型的返回类型
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {return t + u;
}
// 3. lambda表达式
auto lambda = [](int x) -> double { return x * 1.5; };

typedef和using

        C++98中我们⼀般使⽤typedef重定义类型名,也很⽅便,但是typedef不⽀持带模板参数的类型重定义。C++11中新增了using可以替代typedef,using 的别名语法覆盖了 typedef 的全部功能,不少场景还更清晰⼀些,⽐如函数指针的重定义,其次最⼤的变化是⽀持带模板参数重定义的语法。

       语法格式 :

using 类型别名 = 类型;
#include<iostream>
#include <map>
#include <string>
using namespace std;
//typedef map<string, int> CountMap;
//typedef map<string, string> DictMap;
//typedef int DateType;
// typedef void (*Callback)(int);
// using 兼容typedef的⽤法
using CountMap = map<string, int>;
using DictMap = map<string, string>;
using STDateType = int;
using Callback = void (*)(int);
// using⽀持带模板参数的类型重定义
template<class Val>
using Map = map<string, Val>;
template<class Val>
using MapIter = typename map<string, Val>::iterator;
int main()
{Map<int> countMap;Map<string> dictMap;MapIter<int> countIter = countMap.begin();MapIter<string> dictIter = dictMap.begin();return 0;
}

        本期内容就到这里了,喜欢请点个赞谢谢

封面图自取:

http://www.dtcms.com/a/516204.html

相关文章:

  • LayoutManager
  • 网站建设公司盈利分析网站建设需要哪些的ps
  • QML学习笔记(四十六)QML与C++交互:Q_PROPERTY宏映射
  • 培训学校 网站费用购物商城网站建设方案
  • 黑马商城day5-服务保护和分布式事务
  • 【实证分析】地市人才及资本创新要素流动数据集-含代码(2003-2023年)
  • 【学习系列】SAP RAP 16:RAP应用部署集成至Fiori Launchpad 【On-Premise】
  • 01-JavaScript基础
  • 万亿国债助力应急行业-多链路聚合通信路由在应急项目中的解决方案和技术需求
  • CSS3 超实用属性:pointer-events (可穿透图层的鼠标事件)
  • 企业做网站公司有哪些wordpress 积分支付
  • Java线程阻塞状态
  • 网站优化排名软件哪些最好99企业邮箱
  • dify之Web 前端工作流编排(Workflow Builder)
  • 环境变量进阶:本地变量、内建命令与全局属性的深度解析
  • 《图解技术体系》Wonderful talk AI ~~Google AI
  • 咸阳网站建设培训学校国外网站 国内访问速度
  • 建设一个网站的工作方案企业信息公开网查询
  • 半导体晶圆制造关于设备制程几个核心概念及映射关系
  • 欧美购物网站排名国内自动化网站建设
  • DeepSeek-OCR: Contexts Optical Compression 详解
  • 第七章 查找——课后习题解练【数据结构(c语言版 第2版)】
  • 江西建设安全网站公司注册查询核名
  • 常用docker命令速查表
  • 响应式酒店网站模板做公司网站要多久
  • 1号店网站网页特效企业网站建设方案价位
  • spring是如何解决循环依赖的(二级缓存不行吗)?
  • 【Python高级编程】基于正则表达式的爬虫
  • 网站链接改名怎做301口碑好的网站建设商家
  • 软文代写费用昆明关键词优化