zoukankan      html  css  js  c++  java
  • C++11 constexpr使用

    C++11为了提高代码执行效率做了一些改善。这种改善之一就是:生成常量表达式,允许程序利用编译时的计算能力。假如你熟悉模板元编程,你将发现constexpr使这一切变得更加简单。constexpr使我们很容易利用上编译时编程的优势。
    常量表达式主要是允许一些计算发生在编译时,即发生在代码编译而不是运行的时候。这是很大的优化:假如有些事情可以在编译时做,它将只做一次,而不是每次程序运行时。需要计算一个编译时已知的常量,比如特定值的sine或cosin?确实你亦可以使用库函数sin或cos,但那样你必须花费运行时的开销。使用constexpr,你可以创建一个编译时的函数,它将为你计算出你需要的数值,用户的电脑将不需要做这些工作。
     
    1.constexpr初探
    为了使函数获取编译时计算的能力,你必须指定constexpr关键字到这个函数。
    constexpr int multiply (int x, int y)
    {
        return x * y;
    }
    
    // 将在编译时计算
    const int val = multiply( 10, 10 );
    除了编译时计算的性能优化,constexpr的另外一个优势是,它允许函数被应用在以前调用宏的所有场合。
    例如,你想要一个计算数组size的函数,size是10的倍数。如果不用constexpr,你需要创建一个宏或者使用模板,因为你不能用函数的返回值去声明数组的大小。但是用constexpr,你就可以调用一个constexpr函数去声明一个数组。
    constexpr int getDefaultArraySize (int multiplier)
    {
        return 10 * multiplier;
    }
    
    int my_array[ getDefaultArraySize( 3 ) ];
    int a = 4;  //非常量表达式
    getDefaultArraySize(a);  //ok
    constexpr修饰的函数,简单的来说,如果其传入的参数可以在编译时期计算出来,那么这个函数就会产生编译时期的值。但是,传入的参数如果不能在编译时期计算出来,那么constexpr修饰的函数就和普通函数一样了。不过,我们不必因此而写两个版本,所以如果函数体适用于constexpr函数的条件,可以尽量加上constexpr。
     
    2.constexpr修饰函数的限制
    一个constexpr有一些必须遵循的严格要求:
    • 函数中只能有一个return语句(但允许包含typedefs、 using declaration && directives、静态断言等)
    • 只能调用其它constexpr函数
    • 只能使用全局constexpr变量

    注意递归并不受限制,但只允许一个返回语句,那如何实现递归呢?可以使用三元运算符(?:)。例如,计算n的阶乘:

    constexpr int factorial (int n) {
        return n > 0 ? n * factorial( n - 1 ) : 1;
    }

    现在你可以使用factorial(2),编译器将在编译时计算这个值,这种方式运行更巧妙的计算,与内联截然不同。你无法内联一个递归函数。

    3.使用编译时对象
    constexpr修饰类的构造函数,即保证如果提供给该构造函数的参数都是constexpr,那么产生的对象中的所有成员都会是constexpr,该对象也就是constexpr对象了,可用于各种只能使用constexpr的场合。注意,constexpr构造函数必须有一个空的函数体,即所有成员变量的初始化都放到初始化列表中。
    假如你有一个Circle类:

    class Circle
    {
        public:
        constexpr Circle (int x, int y, int radius) : _x( x ), _y( y ), _radius( radius ) {}
        constexpr double getArea () {
            return _radius * _radius * 3.1415926;
        }
    private:
        int _x;
        int _y;
        int _radius;
    };

    将构造函数和getArea声明为constexpr,这样在编译期间,便能构造一个对象并能调用getArea函数获得area:

    constexpr Circle c( 0, 0, 10 );
    constexpr double area = c.getArea();

    4.constexpr vs const的区别

    假如你将一个成员函数标记为constexpr,则顺带也将它标记为了const。如果你将一个变量标记为constexpr,则同样它是const的。但相反并不成立,一个const的变量或函数,并不是constexpr的。
    语义上:
    constexpr:告诉编译器我可以是编译期间可知的,尽情的优化我吧。
    const:告诉程序员没人动得了我,放心的把我传出去;或者放心的把变量交给我,我啥也不动就瞅瞅。
    语法上:
    constexpr是一种比const 更严格的束缚, 它修饰的表达式本身在编译期间可知, 并且编译器会尽可能的 evaluate at compile time. 在constexpr 出现之前, 可以在编译期初始化的const都是implicit constexpr. 直到c++ 11, constexpr才从const中细分出来成为一个关键字, 而 const从1983年 c++ 刚改名的时候就存在了... 如果你初学c++, 应当尽可能的, 合理的使用constexpr来帮助编译器优化代码。

  • 相关阅读:
    [国家集训队]拉拉队排练 Manancher_前缀和_快速幂
    高手过愚人节 Manancher模板题_双倍经验
    [模板]manacher算法
    [POI2011]MET-Meteors 整体二分_树状数组_卡常
    [国家集训队]矩阵乘法 整体二分
    三维偏序(陌上花开) CDQ分治
    博客园美化之旅第一天(CSS图层关系,背景相关设置,字体相关设置)
    力扣题目解答自我总结(反转类题目)
    python插件,pycharm基本用法,markdown文本编写,jupyter notebook的基本操作汇总
    关于小程序websocket全套解决方案,Nginx代理wss
  • 原文地址:https://www.cnblogs.com/DswCnblog/p/6513310.html
Copyright © 2011-2022 走看看