본문으로 건너뛰기
0%
약 3분 (661 단어) ko

Understanding constexpr - Compile-time vs Runtime Evaluation

Categories TechSavvy C++
Tags #TechSavvy #ProgrammingLanguage #C++

constexpr

0. Preface

I’ll be honest - constexpr used to keep me up at night! It was so confusing that I couldn’t stand it anymore, so I decided to write this comprehensive guide.

constexpr is supported in Modern C++ (C++11 and above). The specification of constexpr has been evolving as the STL versions progress.

After looking at various lecture materials and use cases, it seems like everyone uses it differently and understands it differently. While the original author of constexpr certainly had a clear intention, it feels quite different from the initial concept now.

However, there’s one thing everyone commonly asks:

“How is it different from const?”

const is simply constant - once compiled, the data becomes immutable during runtime.

constexpr has a similar intention. Programmers use it to ensure that variables or functions are determined at compile time.

But here’s where constexpr gets a bit ambiguous: variables or functions declared with constexpr can be determined either during compilation OR during runtime! cpp reference c++1x constexpr

Let’s dive into some examples to explore this ambiguity…

1. Regular Example

#include <iostream>
int fibonacci(int n){
    if (n >= 2) 
        return fibonacci(n-1) + fibonacci(n-2);
    else
        return n;
}

int main(){
    std::cout << fibonacci(10) << '\n';
}

Here’s a simple Fibonacci sequence calculator.

This code calculates the value at runtime after compilation.

$ /usr/bin/time ./fibonacci 
102334155
0.56user 0.00system 0:00.56elapsed 100%CPU (0avgtext+0avgdata 3324maxresident)k
0inputs+0outputs (0major+126minor)pagefaults 0swaps

Since the value is calculated at runtime, it takes quite a bit of time.

2. Template Approach

What if we want the efficiency of compile-time calculation? Let’s try C++ Template Meta Programming:

#include <iostream>

template <int N>
struct fibonacci
{
    static int64_t const value = fibonacci<N-1>::value + fibonacci<N-2>::value;
};

template<>
struct fibonacci<0>
{
    static int64_t const value = 0;
};

template<>
struct fibonacci<1>
{
    static int64_t const value = 1;
};

int main(){
    std::cout << fibonacci<40>::value << '\n';
}

Using C++ template techniques, the compiler internally generates code and does the work at compile time.

So fibonacci<40>::value is determined at compile time.

$ /usr/bin/time ./fibonacci_template 
102334155
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 3388maxresident)k
0inputs+0outputs (0major+125minor)pagefaults 0swaps

Since the value was calculated at compile time, the execution time is super fast!

3. constexpr

So what happens when we use constexpr?

#include <iostream>
constexpr int fibonacci(int n){
    return n>=2 ? fibonacci(n-1) + fibonacci(n-2): n;
}

template<int N>
struct constN{
    constN(){ std::cout << N << '\n';}
};

int main(){
    constN<fibonacci(40)> a; // Compile time
    //std::cout << fibonacci(40) << '\n';  //Runtime
}
$ /usr/bin/time ./fibonacci_constexpr 
102334155
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 3412maxresident)k
0inputs+0outputs (0major+125minor)pagefaults 0swaps

Again, fast execution because the value was calculated at compile time!

Here’s the interesting part: constexpr can be used in both forms.

If I uncomment the line in the same code above, the value gets determined at runtime and takes much longer:

$ /usr/bin/time ./fibonacci_constexpr 
102334155
0.55user 0.00system 0:00.55elapsed 99%CPU (0avgtext+0avgdata 3376maxresident)k
0inputs+0outputs (0major+125minor)pagefaults 0swaps

4. Conclusion

As we’ve seen, constexpr can be used at both compile time and runtime.

If the constexpr requirements aren’t met during compilation, it automatically falls back to runtime calculation.

Using constexpr gives you the best of both worlds:

  • You can have values determined at compile time for efficiency
  • You can still use debuggers to inspect runtime values at breakpoints

My conclusion: constexpr is a technique that shows the programmer’s intention that a value could be determined at compile time, but doesn’t guarantee it will be.

It’s like saying “Hey compiler, if you can figure this out at compile time, please do. If not, that’s okay too - just calculate it at runtime.”

Pretty neat, right? 🚀

Share this article

Found this helpful? Share it with your network

Join the Discussion

Share your thoughts and connect with other readers

댓글

GitHub 계정으로 로그인하여 댓글을 남겨보세요. 건설적인 의견과 질문을 환영합니다!

댓글을 불러오는 중...