• C++ 之 constexpr详解


    14天阅读挑战赛

    enum hack

    这是一种很实用的编程的方法,可以利用 enum 的特性促使编译器在编译阶段计算常量表达式的值,如下代码:

    #include
    using namespace std;
    // enum hack
    template<int a , int b>
    struct add{
        enum{
            x = a + b,
            y = a - b
        };
    };
    
    int main(){
    	cout << add<5,6>:: x <<endl;
      	cout << add<5,6>:: y <<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    生成的中间代码为:

    #include
    using namespace std;
    // enum hack
    template<int a, int b>
    struct add
    {
      enum 
      {
        x = a + b, 
        y = a - b
      };
      
    };
    
    /* First instantiated from: insights.cpp:13 */
    #ifdef INSIGHTS_USE_TEMPLATE
    template<>
    struct add<5, 6>
    {
      enum 
      {
        x = 5 + 6, 
        y = 5 - 6
      };
      
    };
    
    #endif
    
    
    int main()
    {
      std::cout.operator<<(add<5, 6>::x).operator<<(std::endl);
      std::cout.operator<<(add<5, 6>::y).operator<<(std::endl);
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    C++14中对constexpr进行了大量的改进

    constexpr lambdas 表达式

    从C++17开始,lambda表达式在条件允许的情况下都会隐式声明为constexpr
    从中可以看出,lambdas 表达式在编译阶段就已经计算出了值。但是要注意constexpr表达式退化的问题(就是退化成普通的函数)

    // constexpr lambdas 表达式
    constexpr int foo()
    {
        return []()
        { return 58; }();
    }
    auto get_size = [](int i)
    { return i * 2; };
    char buffer1[foo()] = {0};
    char buffer2[get_size(5)] = {0};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    constexpr 的内联属性

    class X {
    public:
     static constexpr int num{ 5 };
    };
    
    • 1
    • 2
    • 3
    • 4

    代码中,num是只有声明没有定义的,虽然我们可以通过std::cout << X::num << std::endl输出其结果,但这实际上是编译器的一个小把戏,它将X::num直接替换为了5。如果将输出语句修改为std::cout << &X::num << std::endl,那么链接器会明确报告X::num缺少定义。但是从C++17开始情况发生了变化,static constexpr int num{5}既是声明也是定义,所以在C++17标准中std::cout << &X::num << std::endl可以顺利编译链接,并且输出正确的结果。值得注意的是,对于编译器而言为X::num产生定义并不是必需的,如果代码只是引用了X::num的值,
    那么编译器完全可以使用直接替换为值的技巧。只有当代码中引用到变量指针的时候,编译器才会为其生成定义

    if constexpr

    让代码能够根据编译时的条件进行实例化,主要是用于模板编程中。但是要特别注意这两点:
    if constexpr的条件必须是编译期能确定结果的常量表达式。
    条件结果一旦确定,编译器将只编译符合条件的代码块
    入下是实现一个带精度的减法。

    #include 
    template<class T> bool is_same_value(T a, T b)
    {
     if constexpr (std::is_same<T, double>::value) {
     if (std::abs(a - b) < 0.0001) {
     return true;
     }
     else {
     return false;
     }
     }
     else {
     return a == b;
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用 consteval 声明立即函数

    constexpr声明函数时并不依赖常量表达式上下文环境,在非常量表达式的环境中,函数可以表现为普通函数。不过有时候,我们希望确保函数在编译期就执行计算,对于无法在编译期执行计算的情况则让编译器直接报错。于是在C++20标准中出现了一个新的概念——立即函数
    其实就是可以理解为constexpr的不可退化版本。

    判断常量求值环境

    std::is_constant_evaluated是C++20新加入标准库的函数,它用于检查当前表达式是否是一个常量求值环境,如果在一个明显常量求值的表达式中,则返回true;否则返回false。包含在在 头文件中。

  • 相关阅读:
    OpenResty应用-数据库访问
    Vue04/Vue组件通信、Vue组件父传子 props 传值 及 props 介绍
    【HTML——旋转火焰】(效果+代码)
    Ubuntu 20.04上安装Datalog Disassembly工具的过程
    全志H616芯片 以太网模块初始化失败如何解决?
    一文读懂Persistence One- 如何将Restaking带入Cosmos
    Vue权限控制
    libevent学习——辅助类型和函数
    【华为校招】【校招】【Java】字符串匹配(DP)
    【算法】一文带你从浅至深入门dp动态规划
  • 原文地址:https://blog.csdn.net/qq_43964318/article/details/127414280