C++ 之 constexpr详解

14天阅读挑战赛

enum hack

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

#include<iostream>
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;
}

生成的中间代码为:

#include<iostream>
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;
}

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};

constexpr 的内联属性

class X {
public:
 static constexpr int num{ 5 };
};

代码中,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 <type_traits>
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;
 }
}

使用 consteval 声明立即函数

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

判断常量求值环境

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
const和constexpr是C语言中用于定义常量的两个关键字。 const是一个修饰符,用于声明一个不可改变的常量。在C语言中,我们可以使用const来定义一个常量,一旦被定义后,就不能再改变其值。常量一般用大写字母表示,例如: ``` const int MAX_VALUE = 100; ``` 在上述代码中,MAX_VALUE被定义为一个常量,其值为100,这意味着在程序的其他地方不能再改变MAX_VALUE的值。 constexpr是C++11新增加的关键字,用于在编译时求得表达式的值,并将其作为一个常量。与const类似,constexpr也用于定义常量,但它的需求更加严格。在C++中,constexpr可以用于常量的定义、函数的参数和返回值等。 constexpr的特点是在编译时求值,因此可以提高程序的运行效率。例如: ``` constexpr int square(int x) { return x * x; } int main() { constexpr int num = 5; constexpr int result = square(num); return 0; } ``` 在上述代码中,我们定义了一个constexpr函数square,它接收一个参数x,并返回x的平方。在main函数中,我们使用constexpr定义了一个常量num,并将它作为square函数的参数,得到了一个常量result。 总结来说,const和constexpr都是用于定义常量的关键字。const适用于C语言,用于声明不可改变的常量;constexpr适用于C++11及以后的版本,用于在编译时求得表达式的值,并将其作为一个常量。在实际的开发中,根据具体的需求来选择使用const还是constexpr

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

强大的RGG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值