首页 > 编程语言 >c++ constexpr

c++ constexpr

时间:2023-04-09 20:23:59浏览次数:32  
标签:std return int len constexpr c++ const

c++中,constexpr 让用户显式的声明函数或对象构造函数在编译期会成为常量表达式,这个关键字明确的告诉编译器应该去验证被声明的表达式在编译期就应该是一个常量表达式。

声明为constexpr的变量一定是一个const变量,而且必须用常量表达式初始化:

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

需注意constexpr和const在指针上的区别,constexpt只能对指针本身生效,而不针对指针所指向对象

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

更具体的例子如下

#include <iostream>
#define LEN 10

int len_foo() {
    int i = 2;
    return i;
}
constexpr int len_foo_constexpr() {
    return 5;
}

constexpr int fibonacci(const int n) {
    return n == 1 || n == 2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
}

int main() {
    char arr_1[10];                      // 合法
    char arr_2[LEN];                     // 合法

    int len = 10;
    // char arr_3[len];                  // 非法

    const int len_2 = len + 1;
    constexpr int len_2_constexpr = 1 + 2 + 3;
    // char arr_4[len_2];                // 非法
    char arr_4[len_2_constexpr];         // 合法

    // char arr_5[len_foo()+5];          // 非法
    char arr_6[len_foo_constexpr() + 1]; // 合法

    std::cout << fibonacci(10) << std::endl;
    // 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
    std::cout << fibonacci(10) << std::endl;
    return 0;
}

上例中,len_2虽然是const修饰的常数,但是其不能用来初始化一个数组的大小,因为c++标准里数组的长度必须是一个常量表达式,而不是常数,该行为是ub的。

此外constexpr修饰的函数可用递归,c++14后可在constexpr函数内使用局部变量、循环和分支等简单语句。

巧妙的使用constexpr可用减少代码量,见下例

static std::string generate(const Node& node) {
            return std::visit(        //c++17 std::visit(T,val),使用对象class/泛型Lambdas/重载的Lambdas方式访问val
                [](auto&& arg)->std::string {
                    using T = std::decay_t<decltype(arg)>;    //c++14std::decay_t标记c++11std::decay 类型消除,将数据带有的const,&等修饰符关键字去除
                    if constexpr (std::is_same_v<T, Null>) {
                        return "null";
                    }
                    else if constexpr (std::is_same_v<T, Bool>) {
                        return arg ? "true" : "false";
                    }
                    else if constexpr (std::is_same_v<T, Int>) {
                        return std::to_string(arg);
                    }
                    else if constexpr (std::is_same_v<T, Float>) {
                        return std::to_string(arg);
                    }
                    else if constexpr (std::is_same_v<T, String>) {
                        return generate_string(arg);
                    }
                    else if constexpr (std::is_same_v<T, Array>) {
                        return generate_array(arg);
                    }
                    else if constexpr (std::is_same_v<T, Object>) {
                        return generate_object(arg);
                    }
                },
                node.value);
        }

其中结构体node的成员value是std::variant类型,上例代码使用if constexpr,使得程序在编译器去检测if的合法性,免去了重载多个类型的函数。(二者效果相同)

若此处不采用if constexpr,那么因为编译器无法在运行时确定value的具体类型,该段程序将无法编译成功或运行

 

参考文章:https://blog.csdn.net/janeqi1987/article/details/103542802

https://changkun.de/modern-cpp/zh-cn/02-usability/

标签:std,return,int,len,constexpr,c++,const
From: https://www.cnblogs.com/Explosion556/p/17300950.html

相关文章

  • C++构造函数的调用
    对象特性---构造函数和析构函数构造函数---没有回值也不写void---函数值和类名相同---构造函数可以有参数,因此可以发生重载---程序在调用对象的时候自动调用构造,无须手动调用,只能调用一次析构函数语法---析构函数,没有返回值也不写void---函数名和类名也相同,在名称前加上符号~---......
  • c++Primer 14 重载运算符与类型转换
    除了重载的函数调用运算符operator()之外,其他重载运算符不能含有默认实参。      泛型算法中调用的几元谓词是看函数对象的调用运算符的参数个数。而不是构造函数的参数个数。    转换构造函数只能有一个参数,如果他有多个参数,就无法判断是将哪个参数转......
  • C++数组
    数组C++中的数组是一种特殊类型的变量,它可以存储一组具有相同数据类型的元素,这些元素在内存中是按照一定的顺序排列的。下面是C++数组的一些特点:数组的元素类型必须相同。例如,一个int类型的数组中只能存储int类型的元素。数组的大小是固定的。一旦数组被创建,它的大小就不能再......
  • 如何在Linux环境下配置C/C++环境
    root权限后,使用yum源安装yum-yinstallgccgcc-c++kernel-devel//安装gcc、c++编译器以及内核文件查看GCC版本,看是否安装成功gcc-v出现这个就是安装成功了编译&运行C文件为:gcc-o文件名(无后缀)文件名(有后缀)并回车gcc-otesttest.cC++文件为:g++-o文......
  • C++,OpenCV图形绘制与文字输出(7)
    绘线voidline(InputOutputArrayimg,Pointpt1,Pointpt2,constScalar&color,intthickness=1,intlineType=LINE_8,intshift=0);//线的样式enumLineTypes{FILLED=-1,LINE_4=4,//!<4-connectedlineLINE_8=8,//!<8-connec......
  • MordernC++之左值(引用)与右值(引用)
    左值与右值C++中左值与右值的概念是从C中继承而来,一种简单的定义是左值能够出现再表达式的左边或者右边,而右值只能出现在表达式的右边。inta=5; //a是左值,5是右值intb=a; //b是左值,a也是左值intc=a+b; //c是左值,a+b是右值另一种区分左值和右值的方法是:有......
  • C++函数高级
    目录一.函数的默认参数1.默认参数的性质 2.函数默认参数的注意事项二.函数的占位参数三.函数的重载  1.重载的性质和条件(1)修改参数的个数(2)修改参数的类型(3)修改参数的顺序2.函数重载的注意事项 (1)当引用&作为函数参数(2)不可以用函数的默认参数作为重载条件 一.函数的默认参数1.......
  • C++内存对齐
    0x1什么是内存对齐,为什么需要它?尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的.它一般会以双字节,4字节,8字节,16字节甚至32字节为单位来存取内存,这些存取单位称为内存存取粒度。现在考虑4字节存取粒度的处理器取int类型变量(32位系统),该处理器只能从地址为4......
  • C++伪随机数
    直接上代码吧用的是vs2019#include<iostream>usingnamespacestd;intmain(){ //系统生成随机数//rand()%100生成0~99 srand(time(NULL));//随机数种子,不加这行下一行就是伪随机数 intrandom_num=rand()%100+1;//1-100; //cout<<random_nu......
  • C++ map注意事项
    std::map<int,std::string>map;判断key是否存在时不能使用:std::stringstr=map[9];  //这样不存在时会新增!!!需要这样判断:std::map<int,std::string>::interatoriter;iter=map.find(9);if(iter!=map.end())  //存在else//不存在......