16

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?

AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • 4
    [This reference](http://en.cppreference.com/w/cpp/language/constexpr) (cppreference.com) should be a good start since it even has an example – keyser Dec 14 '14 at 20:39
  • They're designed to replace some of the more common uses of preprocessor macros. – OmnipotentEntity Dec 14 '14 at 20:41
  • 2
    You need to read a basic reference the above link will help it may also be helpful to read some of the questions in the [constexpr tag](http://stackoverflow.com/questions/tagged/constexpr) – Shafik Yaghmour Dec 14 '14 at 20:41
  • You can do all kinds of weird shit with them. https://crazycpp.wordpress.com/2014/10/17/compile-time-strings-with-constexpr/ – Edward Strange Dec 14 '14 at 20:45

4 Answers4

22

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.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 2
    No, for functions it indicates that the function *call* is a constant expression when the invocation substitution says so. (Arguments can be constant expressions but the function call must not necessarily be.) – Columbo Dec 14 '14 at 20:52
  • But what is really the benefit of `constexpr` while nothing can be changed at runtime!? We may have the result of a function with a `constexpr` parameter which evaluates at compile time, hence a good performance (!) But that result is fixed even if the program runs thousands of times. The user can't change the parameter sent to the function to get a different result at compile time. Roughly speaking, we could not have such a `constexpr` function and use a literal number as the result of the function, instead. The outcome of the two scenarios would be the same, both give a fixed result! :| – Franky Feb 19 '22 at 06:35
8

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.

Community
  • 1
  • 1
zmbq
  • 38,013
  • 14
  • 101
  • 171
5

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.

Mushroom Man
  • 400
  • 3
  • 18
  • 2
    Sources - http://www.cprogramming.com/c++11/c++11-compile-time-processing-with-constexpr.html – Irrational Person Dec 14 '14 at 21:10
  • So they can be evaluated at compile time? Nice addition, there is no doubt about it - the compilers never ever had the idea that some functions could be evaluated at compile time. Very clever. – AnArrayOfFunctions Dec 14 '14 at 21:14
  • @Jako: the compiler knew for many functions that they are actually constants. However, the result couldn't be used in contexts where a constant expression is needed according to the language, e.g., when defining values for enumerators, sizes of built-in arrays, or non-type template arguments. Declaring functions and objects as `constexpr` makes their values usable in these contexts. – Dietmar Kühl Dec 14 '14 at 21:38
  • 2
    Consider reformatting your post to indicate you are **directly quoting someone else**. As it stands the majority of it reads as though you are the author when it fact it is word for word in the external link. Some might consider this to be plagiarism. –  Apr 08 '15 at 05:28
  • 1
    @MickyDuncan It was my fault that I didn't have citations and it seemed like I was the author, so I have added citations and reworded and reformatted my post. I hope this solves the issue. – Irrational Person Apr 08 '15 at 07:23
  • @IrrationalPerson Thanks buddy. We all have to learn how to format at some point so don't worry. Down-vote undone :) –  Apr 08 '15 at 08:02
  • @MickyDuncan Thanks, if you have any more suggestions to make this a better answer feel free to edit it. – Irrational Person Apr 08 '15 at 08:03
  • @IrrationalPerson It's looking better. Whilst the citations are good, it's still arguably word for word. A good SO Answer should not be one big quote. Consider adding more of your own content rather than posting a series of quotes. Look here for help: _[Successful vs. unsuccessful paraphrases. The University of Wisconsin - Madison](https://writing.wisc.edu/Handbook/QPA_paraphrase.html)_, . –  Apr 08 '15 at 11:10
  • I have applied the quote style to those paragraphs which you tried to mark as quotes (good that you had the citation) but were missing the block style. I have not marked any other blocks you did not cite as that should be your responsibility. It seems to be ok now. Good luck! –  Apr 08 '15 at 11:25
0

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

Praveer Kumar
  • 912
  • 1
  • 12
  • 25