“constexpr”有什么用途?

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 / set函数使用户实例中某个成员只读时创建额外的内存:

class S
{  
private:
    int _i;

public:
    const int & constexpr i = _i;
};

但是以上所有内容均未编译。有人能否给我一些见解,为什么要引入这个关键字?


4
这个参考链接(cppreference.com)应该是一个很好的起点,因为它甚至有一个例子。 - keyser
它们旨在替代一些常见的预处理器宏的使用。 - OmnipotentEntity
2
您需要阅读一份基础参考文件,上面的链接可以帮助您,同时阅读一些 constexpr 标签 下的问题也可能会有所帮助。 - Shafik Yaghmour
你可以用它们做各种奇怪的事情。https://crazycpp.wordpress.com/2014/10/17/compile-time-strings-with-constexpr/ - Edward Strange
4个回答

22

constexpr 的目标取决于上下文:

  1. For objects it indicates that the object is immutable and shall be constructed at compile-time. Aside from moving operations to compile-time rather than doing them at run-time creating constexpr objects has the added advantage that they are initialize before any threads are created. As a result, their access never needs any synchronization. An example of declaring an object as constexpr would look like this:

    constexpr T value{args};
    

    Obviously, for that to work, args need to be constant expressions.

  2. For functions it indicates that calling the function can result in a constant expression. Whether the result of constexpr function call results in a constant expression depends on the arguments and the definition of the function. The immediate implication is that the function has to be inline (it will implicitly be made so). In addition, there are constraints on what can be done within such a function. For C++11 the function can have only one statement which, for non-constructors, has to be a return-statement. This restriction got relaxed in C++14. For example, the following is a definition of a constexpr function:

    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 值可以在任何需要常量表达式的地方使用。

2
不,对于函数来说,它表明当调用替换语句如此时,函数调用是一个常量表达式。(参数可以是常量表达式,但函数调用不一定要是常量表达式。) - Columbo
但是,constexpr 的好处究竟在哪里呢?因为在运行时什么都不能改变!我们可以使用具有 constexpr 参数的函数的结果,在编译时进行评估,从而获得良好的性能(!)。但是,即使程序运行了数千次,该结果也是固定的。用户无法更改发送到函数的参数以在编译时获得不同的结果。简单来说,我们不能拥有这样的 constexpr 函数,并将文字数字用作函数的结果。两种情况的结果是相同的,都会给出一个固定的结果! :| - Franky

8
我看到的是,constexpr 是将两种 C++ 语言——运行时和编译时的语言组合在一起的一种方式。编译时编程通常称为元编程。
首先有了 C,它有宏。宏实际上是由编译器运行的小程序。它们有 if 语句(称为 #ifdef),变量(用 #define)。甚至有一个完整的脚本语言在编译时运行。
当 C++ 出现时,它只有 C 的宏,没有其他东西。然后出现了 C++ 模板。这引入了一种不同的编译时代码运行方式。C++ 元语言在很大程度上是函数式的,例如允许你使用 带尾递归的循环
在 C++ 11 中,他们决定元编程可以更好地展示,因此引入了 constexpr。现在你可以编写既是 C++ 函数又是元函数的代码。在 C++ 14 中它变得更好,因为 constexpr 函数的限制已经放宽了。

5
以下是Alex Allain在他的《C++11中的Constexpr - 广义常量表达式》一文中总结的几点关于constexpr有用性的要点:
  • 首先,使用constexpr指定符可以使函数或变量的值在编译时确定。
  • constexpr指定符的另一个好处是它可以将宏替换为函数。
  • constexpr还将有助于您的模板元编程。

效率上的好处:

常量表达式……允许某些计算在编译时进行,而不是程序运行时。 (Allain 2)

性能好处:如果某些操作可以在编译时完成,则只需执行一次,而不是每次程序运行时都执行。

其他好处:

这样的变量和函数可以在仅允许编译时常量表达式的地方使用。在对象声明中使用constexpr指定符意味着const。在函数声明中使用constexpr指定符意味着inline。(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


编辑:抱歉,我之前错误地让人以为这些观点是我的,所以我进行了更正,改变了各个部分,并添加了引用以避免剽窃。


2
来源 - http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html - Irrational Person
2
考虑重新格式化您的帖子,以表明您正在直接引用他人。目前大部分内容读起来好像是您是作者,而实际上它是外部链接中的逐字逐句。有些人可能认为这是剽窃行为。 - user585968
1
@MickyDuncan 这是我的错,我没有引用参考文献,导致看起来好像是我是作者,所以我已经添加了引用并重新组织和格式化了我的帖子。我希望这解决了问题。 - Irrational Person
@IrrationalPerson,谢谢伙计。我们都必须学会如何进行格式化,所以不用担心。取消踩的操作已完成 :) - user585968
@MickyDuncan 谢谢,如果您有任何更好的建议使这个答案更好,请随意编辑它。 - Irrational Person
显示剩余4条评论

0

“Can someone give me some insight why constexpr keyword was being introduced?”的答案:

现代C++支持两种不可变性。

1)const

2)constexpr。

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接