首页 > 其他分享 >constexpr语法

constexpr语法

时间:2023-05-25 09:35:22浏览次数:26  
标签:const 常量 int 语法 constexpr 表达式 函数

1.用constexpr修饰变量 

1.1 const

在 C++11 之前只有 const 关键字,从功能上来说这个关键字有双重语义:变量只读,修饰常量,举一个简单的例子:

  1.   void func(const int num)
  2.   {
  3.   const int count = 24;
  4.   int array[num]; // error,num是一个只读变量,不是常量
  5.   int array1[count]; // ok,count是一个常量
  6.    
  7.   int a1 = 520;
  8.   int a2 = 250;
  9.   const int& b = a1;
  10.   b = a2; // error
  11.   a1 = 1314;
  12.   cout << "b: " << b << endl; // 输出结果为1314
  13.   }
  14.    
  • 函数 void func(const int num) 的参数 num 表示这个变量是只读的,但不是常量,因此使用 int array[num]; 这种方式定义一个数组,编译器是会报错的,提示 num不可用作为常量来使用。
  • const int count = 24; 中的 count 却是一个常量,因此可以使用这个常量来定义一个静态数组。另外,变量只读并不等价于常量,二者是两个概念不能混为一谈,分析一下这句测试代码 const int& b = a1;:
  • b 是一个常量的引用,所以 b 引用的变量是不能被修改的,也就是说 b = a2; 这句代码语法是错误的。
  • 在 const 对于变量 a1 是没有任何约束的,a1 的值变了 b 的值也就变了
  • 引用 b 是只读的,但是并不能保证它的值是不可改变的,也就是说它不是常量。


 

 

1.2 constexpr

在 C++11 中添加了一个新的关键字 constexpr,这个关键字是用来修饰常量表达式的。所谓常量表达式,指的就是由多个(≥1)常量(值不会改变)组成并且在编译过程中就得到计算结果的表达式。

在介绍 gcc/g++ 工作流程的时候说过,C++ 程序从编写完毕到执行分为四个阶段:预处理、 编译、汇编和链接 4 个阶段,得到可执行程序之后就可以运行了。需要额外强调的是,常量表达式和非常量表达式的计算时机不同,非常量表达式只能在程序运行阶段计算出结果,但是常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。

那么问题来了,编译器如何识别表达式是不是常量表达式呢?在 C++11 中添加了 constexpr 关键字之后就可以在程序中使用它来修改常量表达式,用来提高程序的执行效率。在使用中建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。

在定义常量时,const 和 constexpr 是等价的,都可以在程序的编译阶段计算出结果,例如:

  1.   const int m = f(); // 不是常量表达式,m的值只有在运行时才会获取。
  2.   const int i=520; // 是一个常量表达式
  3.   const int j=i+1; // 是一个常量表达式
  4.    
  5.   constexpr int i=520; // 是一个常量表达式
  6.   constexpr int j=i+1; // 是一个常量表达式
  7.    

对于 C++ 内置类型的数据,可以直接用 constexpr 修饰,但如果是自定义的数据类型(用 struct 或者 class 实现),直接用 constexpr 修饰是不行的。

  1.   // 此处的constexpr修饰是无效的
  2.   constexpr struct Test
  3.   {
  4.   int id;
  5.   int num;
  6.   };
  7.    

如果要定义一个结构体 / 类常量对象,可以这样写:

  1.   struct Test
  2.   {
  3.   int id;
  4.   int num;
  5.   };
  6.    
  7.   int main()
  8.   {
  9.   constexpr Test t{ 1, 2 };
  10.   constexpr int id = t.id;
  11.   constexpr int num = t.num;
  12.   // error,不能修改常量
  13.   t.num += 100;
  14.   cout << "id: " << id << ", num: " << num << endl;
  15.    
  16.   return 0;
  17.   }
  18.    
  19.    

在第 13 行的代码中 t.num += 100; 的操作是错误的,对象 t 是一个常量,因此它的成员也是常量,常量是不能被修改的。


2.用constexpr修饰函数

2.1 修饰函数

constexpr 并不能修改任意函数的返回值,时这些函数成为常量表达式函数,必须要满足以下几个条件:


1.函数必须要有返回值,并且 return 返回的表达式必须是常量表达式。

  1.   // error,不是常量表达式函数
  2.   constexpr void func1()
  3.   {
  4.   int a = 100;
  5.   cout << "a: " << a << endl;
  6.   }
  7.    
  8.   // error,不是常量表达式函数
  9.   constexpr int func1()
  10.   {
  11.   int a = 100;
  12.   return a;
  13.   }
  14.    
  15.    

函数 func1() 没有返回值,不满足常量表达式函数要求
函数 func2() 返回值不是常量表达式,不满足常量表达式函数要求


2.函数在使用之前,必须有对应的定义语句。

  1.   #include <iostream>
  2.   using namespace std;
  3.    
  4.   constexpr int func1();
  5.   int main()
  6.   {
  7.   constexpr int num = func1(); // error
  8.   return 0;
  9.   }
  10.    
  11.   constexpr int func1()
  12.   {
  13.   constexpr int a = 100;
  14.   return a;
  15.   }
  16.    
  17.    

在测试程序 constexpr int num = func1(); 中,还没有定义 func1() 就直接调用了,应该将 func1() 函数的定义放到 main() 函数的上边。


3.整个函数的函数体中,不能出现非常量表达式之外的语句(using 指令、typedef 语句以及 static_assert 断言、return 语句除外)。

  1.   // error
  2.   constexpr int func1()
  3.   {
  4.   constexpr int a = 100;
  5.   constexpr int b = 10;
  6.   for (int i = 0; i < b; ++i)
  7.   {
  8.   cout << "i: " << i << endl;
  9.   }
  10.   return a + b;
  11.   }
  12.    
  13.   // ok
  14.   constexpr int func2()
  15.   {
  16.   using mytype = int;
  17.   constexpr mytype a = 100;
  18.   constexpr mytype b = 10;
  19.   constexpr mytype c = a * b;
  20.   return c - (a + b);
  21.   }
  22.    

以上三条规则不仅对应普通函数适用,对应类的成员函数也是适用的:

  1.   class Test
  2.   {
  3.   public:
  4.   constexpr int func()
  5.   {
  6.   constexpr int var = 100;
  7.   return 5 * var;
  8.   }
  9.   };
  10.    
  11.   int main()
  12.   {
  13.   Test t;
  14.   constexpr int num = t.func();
  15.   cout << "num: " << num << endl;
  16.    
  17.   return 0;
  18.   }
  19.    
  20.    

 

2.2 修饰模板函数

C++11 语法中,constexpr 可以修饰函数模板,但由于模板中类型的不确定性,因此函数模板实例化后的模板函数是否符合常量表达式函数的要求也是不确定的。如果 constexpr 修饰的模板函数实例化结果不满足常量表达式函数的要求,则 constexpr 会被自动忽略,即该函数就等同于一个普通函数。

  1.   #include <iostream>
  2.   using namespace std;
  3.    
  4.   struct Person {
  5.   const char* name;
  6.   int age;
  7.   };
  8.    
  9.   // 定义函数模板
  10.   template<typename T>
  11.   constexpr T dispaly(T t) {
  12.   return t;
  13.   }
  14.    
  15.   int main()
  16.   {
  17.   struct Person p { "luffy", 19 };
  18.   //普通函数
  19.   struct Person ret = dispaly(p);
  20.   cout << "luffy's name: " << ret.name << ", age: " << ret.age << endl;
  21.    
  22.   //常量表达式函数
  23.   constexpr int ret1 = dispaly(250);
  24.   cout << ret1 << endl;
  25.    
  26.   constexpr struct Person p1 { "luffy", 19 };
  27.   constexpr struct Person p2 = dispaly(p1);
  28.   cout << "luffy's name: " << p2.name << ", age: " << p2.age << endl;
  29.   return 0;
  30.   }
  31.    

在上面示例程序中定义了一个函数模板 display(),但由于其返回值类型未定,因此在实例化之前无法判断其是否符合常量表达式函数的要求:

struct Person ret = dispaly(p); 由于参数 p 是变量,所以实例化后的函数不是常量表达式函数,此时 constexpr 是无效的
constexpr int ret1 = dispaly(250); 参数是常量,符合常量表达式函数的要求,此时 constexpr 是有效的
constexpr struct Person p2 = dispaly(p1); 参数是常量,符合常量表达式函数的要求,此时 constexpr 是有效的

 

2.3 修饰构造函数

如果想用直接得到一个常量对象,也可以使用 constexpr 修饰一个构造函数,这样就可以得到一个常量构造函数了。常量构造函数有一个要求:构造函数的函数体必须为空,并且必须采用初始化列表的方式为各个成员赋值。

  1.   #include <iostream>
  2.   using namespace std;
  3.    
  4.   struct Person {
  5.   constexpr Person(const char* p, int age) :name(p), age(age)
  6.   {
  7.   }
  8.   const char* name;
  9.   int age;
  10.   };
  11.    
  12.   int main()
  13.   {
  14.   constexpr struct Person p1("luffy", 19);
  15.   cout << "luffy's name: " << p1.name << ", age: " << p1.age << endl;
  16.   return 0;
  17.   }
  18.    


3.总结:

1.const用于修饰不能被修改的对象,但const对象的值通常在程序运行期间才能确定

2.constexpr用于修饰常量表达式或可返回常量表达式的constexpr函数,在编译时能确定值。

3.constexpr函数都是inline函数

from:https://blog.csdn.net/m0_52902391/article/details/120308866

 

标签:const,常量,int,语法,constexpr,表达式,函数
From: https://www.cnblogs.com/im18620660608/p/17430201.html

相关文章

  • constexpr学习
    constexptr和常量表达式常量表达式是指值不会改变并且在编译过程中就能得到计算结果的表达式。编译过程中得到计算结果。字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定。(注意!!!)对于这条语......
  • C++11 constexpr:验证是否为常量表达式(长篇神文)
    constexpr是C++11标准新引入的关键字,不过在讲解其具体用法和功能之前,读者需要先搞清楚C++常量表达式的含义。 所谓常量表达式,指的就是由多个(≥1)常量组成的表达式。换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。这也意味着,常量表达式一旦确定,其值......
  • GitlabCI学习笔记之三:GitLabRunner pipeline语法之tags allow_faillure when retry ti
    1.tags用于从允许运行该项目的所有Runner列表中选择特定的Runner,在Runner注册期间,您可以指定Runner的标签。tags可让您使用指定了标签的runner来运行作业,此runner具有ruby和postgres标签。示例给定带有osx标签的OSXRunner和带有windows标签的WindowsRunner,以下作业将在......
  • 八、流水线语法之Directives
    一、environmentenvironment指令指定了一系列键值对,这些键值对将被定义为所有步骤或阶段特定步骤的环境变量,具体取决于环境指令在管道中的位置。该指令支持一个特殊的助手方法credentials(),该方法可用于通过Jenkins环境中的标识符访问预定义的credentials。支持的凭据类型Secret......
  • SQL高级语法学习总结(二)
    SQL高级语法学习总结(一)。现在我们接着说sql的高级用法。SQLCREATEDATABASE语法CREATEDATABASEdbname;CREATEDATABASE语句用于创建数据库。 SQLCREATETABLE语法CREATETABLEtable_name(column_name1data_type(size),column_name2data_type(size),column_name3dat......
  • SQL高级语法学习总结(一)
    基础语法呢,就是简单的对行列进行增删改。SQL基础语法学习总结,高级用法无非是条件更多,能实现的需求更多,其中涉及到非常多的关键字,本篇博客就进行一下总结。本文所有用法均在mysql环境下测试通过。其他数据库可能某些关键字会有不同。SQLSELECTLIMIT子句 SELECTLIMIT子句用于规......
  • 【JavaScript用法】JavaScript(JS)的基本语法(JS数据类型,JS变量,JS运算符,JS流程控制语句
    JavaScript(JS)的基本语法目录JavaScript(JS)的基本语法一.与html结合方式二.注释三.数据类型:四.变量五.运算符(和Java有点类似)六.流程控制语句(和JAVA 类似):七.JS特殊语法:一.与html结合方式       1.内部JS:定义<script>,标签体内容就是js代码(可以理解为和html......
  • ABAP新语法的坑
    1.问题描述新语法:SELECT或者READTABLE...INTODATA(变量名),直接将结果放到变量里面,不用声明变量的类型。看下面的代码,当READTABLElt_aufk没有查到值的时候,不会将空值INTO到结构变量ls_aufk2里面,ls_aufk2还是上一条记录的值。2.解决办法循环外面加上:CLEARls_aufk2."......
  • day104 - jsp语法
    jsp标签页面包含标签(类似vue组件)<%--jsp:include--%><jsp:includepage="jsptag2.jsp"></jsp:include> 请求转发标签其中param可以携带参数<%--请求转发标签--%>页面一:请求转发到页面二<jsp:forwardpage="/jsptag2.jsp"><jsp:paramna......
  • TS语法笔记-1
    第一章快速入门0、TypeScript简介TypeScript是JavaScript的超集。它对JS进行了扩展,向JS中引入了类型的概念,并添加了许多新的特性。TS代码需要通过编译器编译为JS,然后再交由JS解析器执行。TS完全兼容JS,换言之,任何的JS代码都可以直接当成JS使用。相较于JS而言,TS拥有了静态类......