Thursday, December 13, 2012

C++11 Standard Explained: 2. Constant Expression

In this article I will try a different approach, only explaining stuff that is not clearly explained elsewhere.

Before constant expression become the standard, you couldn't do much compile time calculation easily. Constant expression allowed programmer to leverage the power of C++ during compile time, which, for the most of the time, is only useful when you know the real underlining power of it.
constexpr is a new keyword that was proposed, and has been implemented in gcc and clang. It is

What does it not do?

For primitive types, there is no real difference between const and constexpr. 
A simple example:

C++03 code C++11 code
int main() {
    const int i = 100;
    if(i == 100) {
        return 1;
    }
    return 0;
}
int main() {
    constexpr int i = 100;
    if(i == 100) {
        return 1;
    }
    return 0;
}
Assembly code:
    movl    %esp, %ebp
    subl    $16, %esp
    movl    $100, -4(%ebp)
    movl    $1, %eax
    leave

Assembly code:   
    movl    %esp, %ebp
    subl    $16, %esp
    movl    $100, -4(%ebp)
    movl    $1, %eax
    leave


Yeah, you guessed it right: there is no difference at all. Note the compiler I used was g++, and I did not use any optimization option.

When you try it with a POD type such as the following:
struct compNum {
    int m_real;
    int m_img;
    constexpr compNum(int real, int img)
        : m_real(real), m_img(img) {}
};

And use it in constant expression code, such as the following

int main() {
    constexpr compNum curNum(1, 2);
    if(curNum.m_real == 100) {
        return 1;
    }
    return 0;
}

It makes some difference when you do not turn on the optimization option. When you turn on optimization, however, there is absolutely no difference.


So what does it do?

Bottom line: it enables you to do more at compile time. One example of that is:
int main() {
    constexpr char* str = "haha";
    static_assert(str == "haha", "string not the same");
    return 0;
}
Notice the line static_assert, which is one of the new feature in C++11 that I will get on with very soon, is that it allows for compile time assertion, which is similar to boost's static assert. Within static assert, you cannot use const char *. You have to use constexpr char * in this case, because constexpr char * are guaranteed to be available during compile time execution of the line following it.
Constexpr functions are also very nice to use. The following blogpost explains constexpr functions in detail, you may refer to this:
http://cpptruths.blogspot.com/2011/07/want-speed-use-constexpr-meta.html
The key idea for constant expression functions is that you may only have ONE return statement, and you may not declare any variables, therefore you have to be very smart in terms of the recursive function you are going to write to make it useful.
if you want some real code to show the power of constant expression, you can check out a constexpr hash map I wrote last summer.
https://github.com/benjibc/constexpr_hash_map
Anyways, please leave any comment for corrections. Coming up: static_assert.

1 comment: