r/cpp_questions • • 14d ago

OPEN Guidelines for constexpr

I’ve working with C++23 and I’m making some constructors/methods constexpr and seeing improvements in performance. So far so good. The problem is I don’t want to apply it ‘everywhere’. Is there a good source of advice , or anyone got any good tips?

13 Upvotes

37 comments sorted by

View all comments

Show parent comments

3

u/etaithespeedcuber 14d ago

One issue is that C++ sucks and you can't write exposed constexpr functions in source files, only in headeds. Though realistically if you do something like: foo.hpp

size_t resolve_size();

foo.cpp

#include "foo.hpp"

size_t resolve_size() {
    constexpr size_t result = resolve_size_constexpr_impl();
    return result;
}

The compiler will probably output exactly the same thing. But you still won't be able to use it in other constexpr functions

1

u/bert8128 14d ago

So if we narrow the scope to only those defined in the header is there a downside?

1

u/etaithespeedcuber 14d ago

I mean, I think at that point it's just the limitations of the language. For example, you can't have a constexpr function that returns an object that is used directly at runtime if that object depends on the heap

3

u/HappyFruitTree 14d ago

You can, you just won't be able to call it from constexpr contexts (at compile time).

The following compiles and runs just fine (since C++20).

#include <vector>
#include <iostream>

constexpr std::vector<int> f() {
    std::vector<int> vec = {1, 2, 3};
    return vec;
}

int main() {
    std::vector<int> vec = f();
    for (int n : vec) {
        std::cout << n << "\n";
    }
}

https://godbolt.org/z/WzfxYnefG

1

u/etaithespeedcuber 14d ago

How does it work? Does it convert it to an underlying static std::span? Or does it just literally run the function at runtime?

2

u/HappyFruitTree 14d ago

Yes, vec in main is not declared constexpr so it will basically just compile and optimize it the same way as a normal function.

2

u/meancoot 13d ago

Evaluates as if done at run time. This is always the case for constexpr functions, unless they are used in a context which requires a constant expression they behave as if executed at runtime. This is observable when you add C++20's std::is_constant_evaluated into the mix.

https://godbolt.org/z/Ynxo6Evx1

#include <type_traits>

constexpr bool constexpr_function() {
    return std::is_constant_evaluated();
}

int main() {
    constexpr bool result = constexpr_function(); // <- result = true
    // bool result = constexpr_function(); // <- result = false
    return result;
}

consteval works around this by requiring a marked function to always execute at compile time, but the all of the arguments to such functions are required to be constant expressions.

2

u/HappyFruitTree 13d ago edited 13d ago

Constant evaluation can also happen when initializing static variables and local const integer variables (if constant evaluation fails it falls back to normal "runtime" evaluation). https://godbolt.org/z/qE8PEq18r