什么是' constexpr'对...有用?

时间:2014-12-14 20:35:23

标签: c++ c++11 language-lawyer compile-time

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

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

但以上都没有实际编译过。有人可以告诉我为什么要引入这个关键字?

4 个答案:

答案 0 :(得分:17)

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; }
    
  3. 在创建非内置类型的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值可用于预期的常量表达式。

答案 1 :(得分:7)

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

首先是C及其宏。宏实际上是由编译器运行的小程序。他们有if语句(称为#ifdef),变量(带#define)。甚至整个scripting language在编译时运行。

当C ++出现时,它有C宏,仅此而已。然后是C ++模板。这些引入了运行编译时代码的不同的方式。 C ++元语言在很大程度上是功能性的,例如,允许你做loops with tail recursion

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

答案 2 :(得分:4)

以下是Alex Allain在他的&#34; Constexpr - C ++ 11中的广义常量表达式中所提出的观点的总结,&#34;详细信息 constexpr的有用性:

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

有效提高效率:

  

常量表达式......允许某些计算在编译时进行,字面意思是在代码编译时,而不是在程序本身运行时。 (Allain 2)

     

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

其他好处:

  

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

constexpr功能规则:

  
      
  1. 必须包含单一退货声明(少数例外)
  2.   
  3. 它只能调用其他constexpr函数
  4.   
  5. 它只能引用constexpr全局变量(Allain 6)
  6.   

constexpr构造函数的规则:

  
      
  1. 其每个参数必须是文字类型
  2.   
  3. 该类必须没有虚拟基类
  4.   
  5. 构造函数不能具有function-try-block(CPP 6)
  6.   

引文

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

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


编辑:抱歉,我觉得自己似乎是这些要点的作者,所以我已经纠正了自己,更改了各个部分,并添加了引文来避免剽窃。

答案 3 :(得分:0)

答案&#34;有人可以告诉我为什么要引入constexpr关键字吗?&#34;

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

1)const

2)constexpr。

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

示例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上编译的