7

I'm learning the c++ STL and it came to my attention that while most functionalities supported by std::vector and std::array (contiguous storage) are marked with constexpr, that's not the case for std::deque and other non-contiguous storages. So I spent some time doing some research, I found a proposal in 2019, Making std::deque constexpr, and std::deque still has not implemented constexpr for its methods.

My confusion is that std::array guarantees that its elements are stored on the stack; just like a normal C-style array, so it should be computed at compile time, but std::vector allocates memory on the heap so if it's evaluated at compile time, so is deque, right?

Thanks!

1 Answers1

5

According to https://github.com/cplusplus/papers/issues/665 which keeps a log of the progression of the proposal through the standards committee process, there seem to have been some doubts whether a constexpr std::deque can be implemented without core language changes.

Unfortunately it doesn't say what the specific concern is. Probably some common implementation makes use of some language construct that specifically is not allowed in constant expressions or the implementation relies on some construct that is undefined behavior according to the standard. The latter is usually not a problem for the standard library, since it is not bound by the language rules and can make assumptions about the particular compiler's behavior. However in constant expressions core language undefined behavior is always a hard error and therefore such constructs might often not be usable in constant expression contexts without introducing magic compiler workarounds.

As mentioned in the linked github issue, there seem to also be some library facilities which need to have constexpr added to make this work as well.

Aside from such issues, generally, I don't think there is any reason to not make all containers and container adaptors constexpr-friendly now that std::allocator can be used in constant expressions. They probably just want to make sure that they can be properly implemented as constexpr first. My guess is that for the same reason only std::string and std::vector were done with C++20, since these are the simplest and most important allocator-aware containers to apply constexpr to. (std::array has been constexpr for longer since it doesn't require any dynamic allocations.)

Although, looking at the date of the last entry in the issue (as well as the accompanying issues for std::list, std::priority_queue, etc.) it seems to not have progressed in the last two years, maybe because the author of the proposal did not pursue it further, but I can't really tell.


In either case, when we say that std::vector (or other allocator-aware containers) are constexpr-friendly, this means something else than it does for e.g. std::array. You can declare a constexpr std::array variable and use it as you would use a const std::array variables, but you can't declare a constexpr std::vector variable (generally at all) and use it as you would a const std::vector.

What you can do however is use a std::vector variable in e.g. a constexpr function to do some calculations, as long as the variable is created after the evaluation of the constant expression starts and is destroyed before it ends. Currently this is not possible with e.g. a std::list which is not constexpr-friendly.

The reason for this is that the compiler will not actually allocate memory at compile-time for the container and then transfer it in some way into a runtime allocation (whether static or dynamic). Instead dynamic allocations at compile-time are separate from runtime ones and must be deallocated before the constant expression evaluation in which they were allocated ends.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Thank you so much for your detailed information. "I don't think there is any reason to not make all containers and container adaptors constexpr-friendly" -- This is the main reason I was wondering about the STL. Like I mentioned above, I understand that `std::array` is constant-expression friendly because it's computed at compile time. I also look at the source code of both vector and deque and it seems to me that they both use `std::allocator` internally to handle memory management. So I just want to know why most methods in `vector` are constexpr but those in `deque` are not. – Richard H. Nguyen Jun 28 '22 at 20:45
  • @Yuuta Dynamic allocations via `std::allocator` are only `constexpr`-friendly since C++20. When that change was made it became possible to make containers using it also `constexpr`-friendly. At the very least to make a class `constexpr`-friendly you need to put `constexpr` on most or all member functions and that is what would be the main change in the C++ standard which governs the language. But putting `constexpr` on a function is not always enough to make it work. – user17732522 Jun 28 '22 at 21:05
  • For a simple example `reinterpret_cast` is forbidden in constant expressions, so it can't be used in member function definitions if the class is supposed to be `constexpr`-friendly. Before the standards committee can add `constexpr` it must be convinced that the standard library implementers can make their current implementations of the container to allow `constexpr` without major issues. The process of making sure of that takes some time and work and seems to have simply stalled for `std::deque`. From what I can tell in the link, it originally looked like it could have made it for C++23. – user17732522 Jun 28 '22 at 21:05
  • @Yuuta Also look at the polls in the link such as "_We should promise more committee time to pursuing [these proposals] knowing that our time is scarce and this will leave less time for other work._" with some votes against. It shows that there is also simply an issue of prioritizing which language features to spend time working on. Other more significant library types also haven't been `constexpr`-friendly and require committee time, for example `std::unique_ptr` which has been made `constexpr`-friendly recently for the C++23 draft (https://github.com/cplusplus/papers/issues/961). – user17732522 Jun 28 '22 at 21:22