What are 'constexpr' useful for?

﹥>﹥吖頭↗ 提交于 2020-06-09 16:53:29

问题


I really can't find any use of it. My first idea was that I could use it to implement 'Design by Contract' without using macros like this:

struct S
{   
    S(constexpr int i) : S(i) { static_assert( i < 9, "i must be < 9" ); }

    S(int i); //external defintion

    char *pSomeMemory;
};

But this wouldn't compile. I thought we could also use it to reference same-variable without the need of additional memory to be created when we want to avoid the get/setters in order to make instances to one member from users to be read-only:

class S
{  
private:
    int _i;

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

But none of the above actually compiled. Can someone give me some insight why this keyword was being introduced?


回答1:


The goal of constexpr depends on the context:

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

When creating constexpr object of non-built-in types the respective types will need a constexpr constructor: the generated default constructor won't work. Obviously, a constexpr constructor will need to initialize all members. A constexpr constructor could look like this:

struct example {
    int value;
    constexpr example(int value): value(value) {}
};

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

The created constexpr values can be used everywhere a constant expression is expected.




回答2:


The way I see it, constexpr is a way to bring together the two C++ languages - the one that runs at runtime and the one that runs at compile time. Compile time programming is usually called meta-programming.

First there was C, with its macros. Macros were in fact little programs that were ran by the compiler. They had if statements (called #ifdef), variables (with #define). There's even an entire scripting language that runs in compile time.

When C++ came out, it had the C macros and nothing more. Then came the C++ templates. These introduced a different way of running compile-time code. The C++ meta-language was largely functional, allowing you to do loops with tail recursion, for example.

In C++ 11, they've decided that meta-programming can look better, so they've introduced constexpr. Now you can write C++ functions that are also meta-functions. In C++ 14 it gets better, because the restrictions on constexpr functions have been relaxed.




回答3:


Here is a summary of points made by Alex Allain in his "Constexpr - Generalized Constant Expressions in C++11," which details the usefulness of constexpr:

  • First, with a constexpr specifier, the value of the function or variable can be at compile time.
  • Another benefit of the constexpr specifier is that it can replace macros with functions
  • constexpr will also benefit your template metaprogramming.

Benefit to efficiency:

constant expressions...allow certain computations to take place at compile time, literally while your code compiles rather than when the program itself is run. (Allain 2)

Performance benefit: if something can be done at compile time, it will be done once, rather than every time the program runs

Other benefits:

Such variables and functions can then be used where only compile time constant expressions are allowed. A constexpr specifier used in an object declaration implies const. A constexpr specifier used in an function declaration implies inline.(CPP 1)

Rules for constexpr functions:

  1. It must consist of single return statement (with a few exceptions)
  2. It can call only other constexpr functions
  3. It can reference only constexpr global variables (Allain 6)

Rules for constexpr constructors:

  1. each of its parameters must be literal type
  2. the class must have no virtual base classes
  3. the constructor must not have a function-try-block (CPP 6)

Citations

Allain, Alex, "Constexpr - Generalized Constant Expressions in C++11", Unspecified Date, "http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html"

CPP, "Constexpr Specifier", 16 December 2014, http://en.cppreference.com/w/cpp/language/constexpr


EDIT: Sorry, It was my fault to make it seem like I was the author of these points, so I have corrected myself, changed various parts, and added citations to avoid plagiarism.




回答4:


Answer of " Can someone give me some insight why constexpr keyword was being introduced?"

Modern C++ supports two types of immutability.

1) const

2) constexpr.

constexper will be evaluated at the compile time. It is used to specify constness and allows placement of data in the memory where it might be corrupted.

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

}

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

Note: above source code are compiled on VS2015



来源:https://stackoverflow.com/questions/27473795/what-are-constexpr-useful-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!