21xrx.com
2025-03-26 06:36:02 Wednesday
文章检索 我的文章 写文章
常量表达式大杂烩:不是C++整型常量的例子
2023-06-22 12:46:23 深夜i     17     0
常量表达式 不是整型常量 例子 C++ 杂烩

在C++中,常量表达式可以用于变量初始化、数组长度、静态断言等许多场景。常量表达式通俗点讲,就是编译期可求值的表达式。在很多人的印象中,常量表达式好像只能是整型,但其实不是这样的。接下来,我们就来看看常量表达式的大杂烩,也就是不是C++整型常量的例子。

首先,C++11中支持使用constexpr修饰函数,将其变成常量表达式函数,例如:

constexpr int factorial(int n) {
  return n > 1 ? factorial(n - 1) * n : 1;
}
int main() {
  constexpr int res = factorial(5); // 编译期计算
  std::cout << "5! = " << res << std::endl;
  return 0;
}

在上面的例子中,factorial函数使用递归来计算阶乘,而constexpr修饰使得该函数可以在编译期计算,因此可以在main函数中使用它得到编译期常量res的值。

其次,C++11中还引入了nullptr,即空指针常量。nullptr实际上就是一个值为0的空指针,可以用于删除类成员函数上,例如:

class A {
public:
  void foo() const {
    std::cout << "A::foo()" << std::endl;
  }
};
class B : public A {
public:
  void foo() = delete;
};
int main() {
  B b;
  b.A::foo(); // 调用基类函数,会输出"A::foo()"
  // b.foo(); // error: use of deleted function 'void B::foo()'
  return 0;
}

上面的例子中,B类继承A类,但是不希望B类具有A类的foo函数。因此,在B类中使用foo() = delete来删除该函数。在main函数中,我们使用b.A::foo()调用了A类的foo函数,而b.foo()则直接编译失败。

最后,C++14中增加了变长参数模板的支持,在其内部也可以用constexpr修饰函数参数:

template<typename ...T>
constexpr auto sum(T ...t) -> decltype((t + ...)) {
  return (t + ...);
}
int main() {
  constexpr int res1 = sum(1, 2, 3, 4); // 编译期计算
  std::cout << "1+2+3+4 = " << res1 << std::endl;
  int a[sum(1, 2, 3) + 1]; // 变量长度数组
  std::cout << sizeof(a) << std::endl; // 输出12,因为a的长度是6
  return 0;
}

上面的例子中,sum函数使用了变长参数模板来计算传入的所有参数之和,并在返回类型后面使用了decltype((t + ...))语法进行类型推导。在main函数中,我们使用该函数获得编译期常量res1的值,并使用其计算数组a的长度,得出结果为6 * sizeof(int) = 12。

通过上述几个例子,我们可以看到常量表达式确实是非常灵活的,远远不止整型常量那么简单。当然,在实际开发中,常量表达式的应用还有很多,需要我们不断去积累和发掘。

  
  

评论区