constexpr到底是什么?

举报
irrational 发表于 2022/01/18 00:13:09 2022/01/18
【摘要】 constexpr表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。声明为constexpr的变量一定是一个const变量,而且必须用常量表达式初始化:     constexpr int mf = 20;  //20是常量表达式     const...

constexpr表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。声明为constexpr的变量一定是一个const变量,而且必须用常量表达式初始化:

    constexpr int mf = 20;  //20是常量表达式
    constexpr int limit = mf + 1; // mf + 1是常量表达式
    constexpr int sz = size(); //之后当size是一个constexpr函数时才是一条正确的声明语句

指针和constexpr

必须明确一点,在constexpr声明中如果定义了一个指针,限定符conxtexpr仅对指针有效,与指针所指的对象无关。

    const int*p = nullptr;        //p是一个指向整形常量的指针
    constexpr int* q = nullptr;   //q是一个指向整数的常量指针

 p是一个指向常量的指针,q是一个常量指针,其中的关键在于constexpr把它所定义的对象置为了顶层const。


  
  1. #include <iostream>
  2. int main()
  3. {
  4. int i = 10;
  5. int j = 100;
  6. std::cout << "i=" << i << std::endl;
  7. constexpr int* p = &i;
  8. *p = 8;
  9. std::cout << "i=" << i << std::endl;
  10. //p = &j; //error
  11. return 0;
  12. }

结果如下:

使用GNU gcc编译器时,constexpr指针所指变量必须是全局变量或者static变量(既存储在静态数据区的变量)。


  
  1. #include <iostream>
  2. int main()
  3. {
  4. static int bufSize = 512;
  5. std::cout << "bufSize=" << bufSize << std::endl;
  6. constexpr int* ptr = &bufSize;
  7. *ptr = 1024;
  8. std::cout << "bufSize=" << bufSize << std::endl;
  9. return 0;
  10. }

ps:全局变量和局部变量的存储区域不同,全局变量存放在静态数据区,局部变量存放在栈区。但还有一个小点就是存放在静态数据区的变量是由低地址向高地址存放的,但存放在栈区的变量却是由高地址向低地址存放的,存放在静态数据区的还有静态局部变量和静态全局变量。
 

constexpr函数

    constexpr函数是指用于常量表达式的函数。

    遵循以下规定:(1)函数的返回类型以及所有形参的类型都得是字面值类型;(2)函数体中必须只有一条return语句。


  
  1. #include<iostream>
  2. using namespace std;
  3. constexpr int new_sz() {
  4. return 42;
  5. }
  6. int main(int argc, char* argv[]) {
  7. constexpr int foo = new_sz();
  8. cout << foo << endl; //42
  9. getchar();
  10. return 0;
  11. }

    分析:我们把new_sz定义成无参的constexpr函数。因为编译器能在程序编译时验证new_sz函数返回的是常量表达式,所以可以用new_sz函数初始化constexpr类型的变量foo。

    执行该初始化任务时,编译器把对constexpr函数的调用替换成其结果值。为了在编译过程中随时展开,constexpr函数被隐式地指定为内联函数。

    constexpr函数体内也可以含有其他语句,只要这些语句在运行时不执行任何操作就行(求解答?)。例如,constexpr函数中可以有空语句、类型别名以及using声明。


  
  1. constexpr int size() { //返回值类型为字面值类型
  2. ; //空语句
  3. using In = int; //using声明
  4. typedef int INT; //类型别名
  5. return 10;
  6. }

    我们允许constexpr函数的返回值并非一个常量。当scale的实参是常量表达式,它的返回值也是常量表达式,反之则不然:


  
  1. #include<iostream>
  2. using namespace std;
  3. constexpr int size() {
  4. ;
  5. using namespace std;
  6. typedef int INT;
  7. return 10;
  8. }
  9. constexpr int new_sz() {
  10. return 42;
  11. }
  12. //如果arg是常量表达式,则scale(arg)也是常量表达式
  13. constexpr size_t scale(size_t cnt) {
  14. return new_sz()*cnt;
  15. }
  16. int main(int argc, char* argv[]) {
  17. int arr[scale(2)]; //正确
  18. //int i = 2;
  19. //int arr2[scale(i)]; //错误:scale(i)不是常量表达式
  20. const int j = 2;
  21. int arr3[scale(j)]; //正确
  22. getchar();
  23. return 0;
  24. }

    把内联函数和constexpr函数放在头文件中:
        和其他函数不一样,内联函数和constexpr函数可以在程序中多次定义。毕竟,编译器要想展开函数仅有函数声明是不够的,还需要函数的定义。不过,对于某个给定的内联函数或者constexpr函数来说,它的多个定义必须完全一致。基于这个原因,内联函数和constexpr函数通常定义在头文件中。

文章来源: blog.csdn.net,作者:irrationality,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_54227557/article/details/120608811

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。