0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C++能不能让编译器自动推导变量类型吗

Wildesbeast 来源:今日头条 作者:IT刘小虎 2024-10-24 17:22 次阅读

随着计算机性能的持续提升,编程语言似乎迎来了一次大爆发,各种编程语言不断出现,乐意折腾的人总能找到一门适合自己胃口的编程语言。

总能找到一门适合自己胃口的编程语言

程序员的口味大体可以分为两种:一是追求极致程序效率,一是追求极致开发效率。抛开稍显晦涩的汇编语言不谈,前者以C语言程序员为代表,C语言语法简单,可控性强,更贴近机器,适合开发超高效率的程序。后者则以各种偏脚本化的语言程序员为代表,这类编程语言更贴近人类,因此开发效率很高。

Python程序中变量的类型

下面是一段 Python 代码,可以看出,Python 程序员在定义变量时,甚至无需关心变量的类型,只需写出核心逻辑即可:

#!/usr/bin/python # -*- coding: UTF-8 -*- counter = 100 # 赋值整型变量 miles = 1000.0 # 浮点型 name = "John" # 字符串

不过,程序中变量的数据类型本质上是用于告诉计算机其占用内存的大小,以及该如何解释这段数据的。所以,即使是 Python 程序,在运行时也需要确定变量的类型,否则计算机就不知道如何存储和解释程序中的变量。当然了,由于上面这段代码没有显式的指定变量类型,所以确定数据类型的工作只能交给编译器(或者说解释器)了。

Python使用变量非常简单

C++程序中变量的类型

不要小看 Python 的这个特性,这可以省去相当多的“键盘敲击次数”。作为实例,可以参考下面这段C++程序片段:

... std::list cars_list; ... std::list::iterator it; for (it=cars_list.begin(); it!=cars_list.end(); it++) { ... }

这个“定义”过程需要敲击相当多的字符

为了遍历 list 中的元素,上述C++代码定义了迭代器it,可以看出,这个“定义”过程需要敲击相当多的字符:“std::list::iterator ”。若是C++也允许像Python那样,无需显式的指定变量类型,而是把变量类型的确认工作交给编译器,代码就简洁许多了:

... std::list cars_list; ... for (it=cars_list.begin(); it!=cars_list.end(); it++) { ... }

代码简洁许多

这样的C++代码并不影响阅读,熟悉 list 的程序员一眼就能看出it是一个迭代器。

可能有读者觉得将“确认变量类型”的工作交给编译器会降低编译效率,但是其实仔细想一下,应该并非如此,请看下面这段C++代码:

int a = 0; int *p = &a; a = p;

编译器在处理第三行代码时,大都会报错,给出类似于下面这样的信息

error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]

这说明C++编译器在处理变量赋值时,也需要确定右值的类型,因此从理论上来看,自动推导类型并不会带来多少额外的工作。

C++中的auto关键字

事实上,C++11标准的确增加了“变量类型自动推导”的功能,只不过不像 Python,C++的这一功能需要借助auto关键字。

其实早在C++98标准中,就已经存在auto关键字了,只不过那时的auto关键字仅用于声明变量拥有自动的生命周期,可是不使用 auto 关键字定义的变量仍然具有自动的生命周期,所以那时的 auto 关键字属于多余的特性。

C++11标准丢弃了auto关键字之前的特性,取而代之的,将此关键字用于定义“可自动推导类型”的变量。下面是一段C++代码示例,请看:

int a = 8; auto b = a; // 自动推导 b 的类型为 int cout << typeid(b).name() << endl;

自动推导类型的C++代码示例

编译这段C++代码时应注意指定C++11标准:

# g++ t.cpp -std=c++11 # ./a.out i

可见,程序输出了i,表示变量 b 为 int 类型,这说明auto关键字的确根据 b 的右值(int型的a)确定了 b 的类型为 int。

现在有了auto关键字,前面那个遍历 list 的C++代码片段就可以改写了,请看:

for (std::list::iterator it=cars_list.begin(); it!=cars_list.end(); it++){ ... } // 现在可以改写为 for (auto it=cars_list.begin(); it!=cars_list.end(); it++){ ... }

显然简洁了许多

显然简洁了许多,C++程序员也可以少敲很多次键盘,手指健康得到了一定程度的保护。

C++的 auto 关键字用于模板

上面只是C++中 auto 关键字的其中一种用法,事实上,auto 关键字不仅仅能够让程序员少敲代码,也能带来一些功能上的便利。例如,在定义模板函数时,用于声明依赖模板参数的变量类型,下面是一段C++代码示例:

template void add(_Tx x, _Ty y) { auto v = x+y; std::cout << v; }

请注意变量 v 的定义,如果这里不使用 auto 关键字就棘手多了,因为我们根本无法事先确定变量 x 和 y 的类型,不到编译的时候,谁能知道 x+y 的结果究竟是什么类型呢?

谁能知道 x+y 的结果究竟是什么类型呢?

读者应该注意到上面的 add() 函数其实并不好用,因为它没有将结果返回给调用者。于是可以做如下修改,请看相关C++代码:

template auto add(_Tx x, _Ty y) { return x+y; }

可见,auto 关键字也可用于自动推导模板函数的返回值类型,否则 add() 函数的返回值类型也是相当难确定的。不过,在编译这段C++代码时,发现如下警告信息:

warning: ‘add’ function uses ‘auto’ type specifier without trailing return type [enabled by default] auto add(_Tx x, _Ty y)

要避免出现这样的警告信息,可以使用C++11标准引入的新关键字decltype,相关的C++代码如下,请看:

template auto add(_Tx x, _Ty y)->decltype(x+y) { return x+y; }

auto用于定义模板函数

auto 在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置,真正的返回值是后面的decltype(x+y)。现在编译这段C++代码,可以得到如下输出,请看:

# g++ t.cpp -std=c++11 # ./a.out 9.14 7 145

注意事项

auto 关键字的“自动推导类型”功能是由编译器提供的,而编译器也不是占卜得到变量类型的,它需要知道一些信息,因此 auto 在定义变量时必须初始化:

int i = 3; auto j = i;

只有这样,编译器才能根据右值的类型推导出 auto 变量的类型。也正是因为如此,auto 变量作为函数的参数是非法的:

// 非法 void foo(auto a){ ... }

若是使用 auto 关键字在同一行定义多个变量,这些变量必须是同一类型,否则编译器就会报错,例如下面这两行C++代码:

auto a1 = 1, a2 = 2;//正确 auto b1 = 10, b2 = 'a';//错误,没有推导为同一类型

如果 auto 变量初始化时的右值为引用,则去除引用。请看下面这段C++代码:

int a = 1; int &b = a; auto c = b; // 此时 c 的类型为 int c = 100; // a 依然为 1

如果希望自动推导为引用类型,则需要配合&运算符:

auto &d = b; d = 100; // 此时 a 为 100

类似的,如果初始化表达式带有 const 或者 volatile 修饰符,仅有 auto 定义的变量去除 const 和 volatile 修饰符。

最后要说明的是,C++中的 auto 关键字并不是真正的类型,它仅用于告诉编译器“应该自动推导变量的类型”,所以像 sizeof() 以及 typeid() 这样操作数据类型的操作符是不能用于 auto 的,下面这两行C++代码是非法的:

size = sizeof(auto); // 非法 cout << typeid(auto).name() << endl; // 非法

小结

本节主要讨论了C++11标准中的 auto 关键字,可见,它不仅能够让程序员少敲键盘,提升了C++程序开发效率,还额外提供了一些功能上的便利。文章在最后还讨论了使用 auto 关键字的注意事项,希望对读者有所帮助。

点个关注吧

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C++
    C++
    +关注

    关注

    22

    文章

    2105

    浏览量

    73513
  • 编译器
    +关注

    关注

    1

    文章

    1618

    浏览量

    49060
  • 变量
    +关注

    关注

    0

    文章

    613

    浏览量

    28337
收藏 人收藏

    评论

    相关推荐

    C语言中结构体能不能相加

    C语言中,结构体能不能相加?
    的头像 发表于 12-19 17:04 1222次阅读
    <b class='flag-5'>C</b>语言中结构体<b class='flag-5'>能不能</b>相加

    能不能把导入的工程的编译器也修改为argmgcc呢?

    KEil MDK工程导入RTT-STUDIO后,工程上右键,点击“构建设置”菜单,设置页面出不来,一点反应没有.另外,我的理解是,导入的工程感觉还是用的KEIL MDK做编译器,而原生的RTT-STUDIO工程是用的armgcc。能不能把导入的工程的
    发表于 02-21 10:08

    C++编译器数值性能比较

    现在市面上,主流的C/C++编译器包括M$的CL、gcc、Intel的icl、PGI的pgcc及Codegear的bcc(原来属于Borland公司)。Windows上使用最多的自然是cl,而在更广阔的平台上,gcc则是
    发表于 09-10 11:54 8次下载

    MATLAB 64位C语言和C++编译器应用程序免费下载

    本文档的主要内容详细介绍的是MATLAB 64位C语言和C++编译器应用程序免费下载。
    发表于 05-21 08:00 4次下载
    MATLAB 64位<b class='flag-5'>C</b>语言和<b class='flag-5'>C++</b><b class='flag-5'>编译器</b>应用程序免费下载

    EE-88:使用21xx编译器初始化C语言中的变量

    EE-88:使用21xx编译器初始化C语言中的变量
    发表于 05-19 21:08 1次下载
    EE-88:使用21xx<b class='flag-5'>编译器</b>初始化<b class='flag-5'>C</b>语言中的<b class='flag-5'>变量</b>

    阿里云基础软件C/C++编译器的工作现状及挑战

    本文主要详细介绍了阿里云CC++编译器(GCC、LLVM)工作现状、主流编译器(GCC、LLVM)开源社区参与现状以及多架构(RISC-V)对数据中心的挑战。
    的头像 发表于 06-23 15:26 2936次阅读
    阿里云基础软件<b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>编译器</b>的工作现状及挑战

    SuperH C/C++ 编译器包 V.9.04 用户手册

    SuperH C/C++ 编译器包 V.9.04 用户手册
    发表于 01-12 18:45 1次下载
    SuperH <b class='flag-5'>C</b>/<b class='flag-5'>C++</b> <b class='flag-5'>编译器</b>包 V.9.04 用户手册

    指针能不能作为循环变量

    指针能不能作为循环变量
    的头像 发表于 02-16 18:11 1010次阅读

    C/C++编译器的缺省字节对齐方式

    C/C++编译器的缺省字节对齐方式为自然对界。即在缺省情况下,编译器为每一个变量或是数据单元按其自然对界条件分配空间。
    的头像 发表于 04-15 11:24 964次阅读

    SuperH C/C++ 编译器包 V.9.01 用户手册

    SuperH C/C++ 编译器包 V.9.01 用户手册
    发表于 04-21 19:55 0次下载
    SuperH <b class='flag-5'>C</b>/<b class='flag-5'>C++</b> <b class='flag-5'>编译器</b>包 V.9.01 用户手册

    SuperH C/C++ 编译器包 V.9.04 用户手册

    SuperH C/C++ 编译器包 V.9.04 用户手册
    发表于 07-03 18:38 4次下载
    SuperH <b class='flag-5'>C</b>/<b class='flag-5'>C++</b> <b class='flag-5'>编译器</b>包 V.9.04 用户手册

    C7000优化C/C++编译器

    电子发烧友网站提供《C7000优化C/C++编译器.pdf》资料免费下载
    发表于 10-30 09:45 0次下载
    <b class='flag-5'>C</b>7000优化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>编译器</b>

    TMS320C6000优化C/C++编译器v8.3.x

    电子发烧友网站提供《TMS320C6000优化C/C++编译器v8.3.x.pdf》资料免费下载
    发表于 11-01 09:35 0次下载
    TMS320<b class='flag-5'>C</b>6000优化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>编译器</b>v8.3.x

    MSP430优化C/C++编译器v21.6.0.LTS

    电子发烧友网站提供《MSP430优化C/C++编译器v21.6.0.LTS.pdf》资料免费下载
    发表于 11-08 14:57 0次下载
    MSP430优化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b><b class='flag-5'>编译器</b>v21.6.0.LTS

    C语言中申请的堆内存能不能自动释放

    C语言中申请的堆内存能不能自动释放?每次都要手动 free 太麻烦,也容易忘记。 学过 C++ 的同学,应该首先能想到智能指针。 但是这是C
    的头像 发表于 11-27 09:33 39次阅读