Why aren't std::algorithms constexpr and which could be?

家住魔仙堡 提交于 2019-12-01 02:05:38
ForEveR

It could be constexpr, but cannot be evaluated as a constant expression, since in this case, for example for compile-time find it is required that: begin/end should be constexpr, the * operator of the iterator should be constexpr, operator == should be constexpr, operator != for the iterator should be constexpr, operator ++ for the iterator should be constexpr. But, if all functions are constexpr, then many algorithms can be implemented with constexpr.

You can look at the SPROUT library for the implementation of constexpr containers/algorithms.

And related talk on the isocpp.org forums

Functions cannot be overloaded based on constexpr-ness. As a result, any function defined as constexpr needs to be implemented in a form which could be a constexpr. This requirement imposes constraints on all implementations.

The C++14 specification is somewhat relaxed with respect to the constraints compared to C++11. However, when the specification was finalized nobody was confident that all optimizations which can be achieved without the constexpr constraint can be achieved when algorithms are mandated to be constexpr. Without knowing that the non-constexpr functionality is not impeded by mandating constexpr implementations the algorithms won't be defined to be constexpr. The non-constexpr use of algorithms is still assumed to be the primary use of algorithms.

It may be worth having a special set of algorithms which are defined to be constexpr. I'm not aware of a correspnding proposal. I also don't see a lot if demand warranting standardization but my perception may be different from other's.

TemplateRex

The current (C++14) Standard Library is pretty much under-powered w.r.t. to the corresponding Core Language capabilities concerning constexpr.

E.g., MSVC 2015, which only has C++11 language support for constexpr, could almost fully implement the entire C++14 Standard Library usage of constexpr. The only exceptions were std::min, std::max, std::minmax, std::min_element, std::max_element, std::minmax_element for std::initializer_list.

As of C++1z (17?), the std::xxx_element algorithms will become constexpr algorithms for general iterator and comparator inputs to unify the usage for std::initializer_list. Furthermore, there are proposals for constexpr lambda functions for C++1z as well.

With lambdas being upgraded, there are still a few core language limitations left to prevent the entire <algorithm> header from becoming constexpr. (Note that these are not hard-core technological obstacles, most of them could be resolved by allowing the compiler to evaluate them).

  1. Some algorithms can dynamically allocate memory by calling std::get_temporary_buffer (std::inplace_merge, std::stable_sort and std::stable_partition) which is not allowed in constexpr contexts.
  2. Some algorithms can fall back to low-level C routines such as memset (std::fill and std::fill_n) that would prevent library authors from using these algorithms in constexpr contexts.
  3. Some algorithm implementations can benefit from the judicious use of goto (e.g. std::nth_element, std::stable_sort), for which a C++1z proposal was rejected.
  4. Last but not least, constexpr is an interface change, promising that all future implementations will have to deliver this promise. For that reason, implementations are not allowed to add constexpr as a Quality of Implementation feature (in contrast to noexcept).

Especially the 4th issue stalls the experimentation with how much constexpr could be pushed for the Standard Library (algorithms, containers and other utilities). Instead, a separate proposal has to be written and approved for every expansion of constexpr.

This is the subject of Antony Polukhin's proposal P0202:

Add Constexpr Modifiers to Functions in and Headers

which I hope would be adopted by the C++ Library Evolution Working Group and make its way into C++20.

std::algorithm algorithms act on iterators. There is a technical reason why making them constexpr would usually either prevent compiling them (in C++11) or do nothing (in C++14 or with conditional-constexpr), but there's also a semantic reason why it wouldn't make sense for them to be constexpr.

The technical reason is that constexpr functions cannot call non-constexpr expressions. ForEveR points out that template constexpr functions can't be evaluated at compile-time if they call non-constexpr expressions.

In the case of std::algorithm, evaluating constexpr functions in std::algorithm would require the functions for accessing container iterators to be constexpr, which in turn would require the iterators themselves to be constexpr types. But this is impossible almost by definition; containers are typically designed as lightweight access to heap-allocated memory, but heap memory cannot be allocated at compile time (of course). In the comments below, dyp points out that iterators don't always point to containers, but even these iterators are unlikely to be useable at compile-time; for instance, streams objects are of course not readable or writeable at compile time, since IO cannot be done at compile time.

This leads to the semantic problem: constexpr semantically means that a function is intended to be possible to evaluate at compile time. Declaring functions conditionally-constexpr when it is impossible to evaluate them at compile time would make the API confusing and misleading.

Now, I think the language would be improved if there were a way to create and use containers at compile time; this would make constexpr that much more similar to Lisp's macro capabilities. This may eventually be added, but currently it's not really supported by existing standard library code. The most flexible approach, of allowing some objects to live on the heap during compile time, is, as mentioned above, not supported at all by the core language, and it would create some serious complications. For instance, what would it be legal to do with such objects? Either their lifetimes would need to be limited to compile-time only, or they would need to be included as static const memory in the final program (like a string literal), or...what?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!