'constexpr'有什么用?

What are 'constexpr' useful for?

本文关键字:constexpr 什么      更新时间:2023-10-16

我真的找不到它的任何用处。我的第一个想法是,我可以使用它来实现"合同设计",而无需使用这样的宏:

struct S
{   
    S(constexpr int i) : S(i) { static_assert( i < 9, "i must be < 9" ); }
    S(int i); //external defintion
    char *pSomeMemory;
};

但这不会编译。我认为我们也可以使用它来引用同变量,而无需在我们想避免 get/setter 以使用户的一个成员的实例成为只读时创建额外的内存:

class S
{  
private:
    int _i;
public:
    const int & constexpr i = _i;
};

但以上这些都没有真正编译。有人可以给我一些见解,为什么引入这个关键字?

constexpr的目标取决于上下文:

  1. 对于对象,它表示对象是不可变的,应在编译时构造。除了将操作移动到编译时而不是在运行时创建constexpr对象之外,还有一个额外的优势,即在创建任何线程之前初始化它们。因此,他们的访问永远不需要任何同步。将对象声明为 constexpr 的示例如下所示:

    constexpr T value{args};
    

    显然,要做到这一点,args需要是常量表达式。

  2. 对于函数,它表示调用函数可以产生常量表达式。constexpr函数调用的结果是否生成常量表达式取决于函数的参数和定义。直接的含义是必须inline函数(它将隐式地如此(。此外,在此类函数中可以执行的操作也存在限制。对于 C++11,函数只能有一个语句,对于非构造函数,该语句必须是 return 语句。这一限制在C++14中放宽。例如,以下是constexpr函数的定义:

    constexpr int square(int value) { return value * value; }
    

创建非内置类型的对象constexpr相应的类型将需要constexpr构造函数:生成的默认构造函数将不起作用。显然,constexpr构造函数需要初始化所有成员。constexpr构造函数可能如下所示:

struct example {
    int value;
    constexpr example(int value): value(value) {}
};
int main() {
    constexpr example size{17};
    int array[size.value] = {};
}

创建的constexpr值可以在需要常量表达式的任何地方使用。

在我看来

constexpr是一种将两种C++语言结合在一起的方法 - 一种在运行时运行,另一种在编译时运行。编译时编程通常称为元编程。

首先是C,它的宏。宏实际上是由编译器运行的小程序。他们有if语句(称为#ifdef(,变量(带#define(。甚至还有一种完整的脚本语言在编译时运行。

当C++出来时,它有C宏,仅此而已。然后是C++模板。这些引入了运行编译时代码的不同方法。C++元语言在很大程度上是功能性的,例如,允许你使用尾递归进行循环。

在C++ 11中,他们认为元编程可以看起来更好,因此他们引入了constexpr。现在,您可以编写C++函数,这些函数也是元函数。在 C++ 14 中,情况变得更好,因为对 constexpr 函数的限制已经放宽。

以下是

Alex Allain在他的"Constexpr - C++11中的广义常量表达式"中的观点摘要,其中详细介绍了constexpr的有用性:

  • 首先,使用constexpr说明符,函数或变量的值可以在编译时。
  • constexpr说明符的另一个好处是它可以用函数替换宏
  • constexpr也将使您的模板元编程受益。

对效率的好处:

常量表达式...允许某些计算在编译时进行,实际上是在代码编译时而不是在程序本身运行时进行。(阿兰2(

性能优势:如果某些事情可以在编译时完成,它将完成一次,而不是每次程序运行时

其他好处:

然后,可以在只允许编译时常量表达式的情况下使用此类变量和函数。对象声明中使用的 constexpr 说明符意味着 const。函数声明中使用的 constexpr 说明符意味着内联。(CPP 1(

constexpr函数的规则:

  1. 它必须由单个返回语句组成(少数例外(
  2. 它只能调用其他 constexpr 函数
  3. 它只能引用 constexpr 全局变量 (Allain 6(

constexpr构造函数的规则:

  1. 其每个参数都必须是文本类型
  2. 该类不得具有虚拟基类
  3. 构造函数不得具有函数尝试块 (CPP 6(

引文

Allain, Alex, "Constexpr - C++11 中的广义常量表达式", 未指定日期, "http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html">

CPP,"Constexpr Specifier",2014 年 12 月 16 日,http://en.cppreference.com/w/cpp/language/constexpr


编辑:对不起,让我看起来像是这些观点的作者是我的错,所以我纠正了自己,更改了各个部分,并添加了引用以避免抄袭。

回答"有人能给我一些见解,为什么引入 constexpr 关键字?

现代C++支持两种类型的不变性。

1( 常量

2(共生。

constexper将在编译时进行评估。它用于指定恒常性,并允许将数据放置在可能损坏的内存中。

示例 1:

void UseConstExpr(int temp)
{
    // This code snippet is OK
    constexpr int y = max + 300;
    std::cout << y << std::endl;
    // This code snippet gives compilation error
    // [ expression must have a constant value]
    constexpr int z = temp + 300;
}

示例 2:

int addVector(const std::vector<int>& inVect)
{
    int sum = 0;
    for ( auto& vec : inVect)
    {
        sum += vec;
    }
    std::cout << sum << std::endl;
    return sum;
}
int main()
{
    // vInt is not constant
    std::vector<int> vInt = { 1,2,3,4,5,6 }; 
    // This code snippet is OK
    // because evaluated at run time
    const int iResult = addVector(vInt);
    // Compiler throws below error
    // function call must have a constant value in a constant expression
    // because addVector(vInt) function is not a constant expression
    constexpr int iResult = addVector(vInt);
    return 0;
}

注:以上源码编译于VS2015