Currently for example when eyeballing the implementation of a number of math functions you will find things like:
std::sqrt(...);
std::tan(...);
calling underlying functions in cmath.h
_NODISCARD _Check_return_ inline float sqrt(_In_ float _Xx) noexcept /* strengthened */ {
return _CSTD sqrtf(_Xx);
}
_NODISCARD _Check_return_ inline float tan(_In_ float _Xx) noexcept /* strengthened */ {
return _CSTD tanf(_Xx);
}
and further calling functions in corecrt.h
Although these functions could be considered pure and otherwise perfectly fine to be used at compile time. The underlying calls lacking constexpr prevents this.
Seems to me given this function buried in vector, which appears to be able to check whether the function is being used at compile time, that these functions can be rewritten constexpr while leaving the runtime behavior intact.
#if _HAS_IF_CONSTEXPR
template <class _InIt, class _OutIt>
_CONSTEXPR20 _OutIt _Move_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest) {
// move [_First, _Last) to [_Dest, ...)
// note: _Move_unchecked has callers other than the move family
if constexpr (_Ptr_move_cat<_InIt, _OutIt>::_Trivially_copyable) {
#ifdef __cpp_lib_is_constant_evaluated
if (!_STD is_constant_evaluated())
#endif // __cpp_lib_is_constant_evaluated
{
return _Copy_memmove(_First, _Last, _Dest);
}
}
for (; _First != _Last; ++_Dest, (void) ++_First) {
*_Dest = _STD move(*_First);
}
return _Dest;
}
The answer is yes, if someome writes a paper for that.
An implementation is not allowed to strengthen constexpr, as that would effectively make the code non-portable.
Not sure what strengthen means, but if there's any confusion, obviously the run time and compile time results should be the same. It's not clear to me in having spotted this whether the compiler would appreciate a call to the crt which isn't constexpr. Presumably the functions would look like:
#if _HAS_IF_CONSTEXPR
constexpr return_type function(params, ...){
if(!::std::is_constant_evaluated()) {
return crt_call(params,...);
} else {
return //crt equivalent compile time code
}
}
#else
...current implementation
#endif
Not sure that deserves much of a paper.
Not sure that deserves much of a paper.
100% must be a paper.
And there are such papers:
You can use the implementations before the papers are not accepted by the commitee:
for cstring:
paper: https://github.com/Neargye/WG21/blob/master/P1944/P1944R0.pdf
implementation: https://github.com/Neargye/cstring-constexpr-proposal
for math:
paper: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1383r0.pdf
constexpr math library: https://github.com/kthohr/gcem
Given this appears not to be the first time someone's brought up whether if(!::std::is_constant_evaluated()) can be used to solve this I guess this could count as some user feedback for the need for this to get solved. Glad I asked the question, because there's no way I would've found those libraries, I'll definitely be using those in the meantime.
Not sure what strengthen means,
To elaborate a bit. The implementation is allowed to strengthen for example the exception specification of a function.
While the standard says the function meow may throw, we can strengthen it to meow may only throw if whatever condition
Importantly this does not affect the validity of the program at all. It might allow for some compiler optimizations but whether you compile the program using standard library A or standard library B, does not change whether this program compiles at all.
That is not true for constexpr. Say we strengthen one of the math functions because our compiler has a special intrinsic for that and you use that function in a constexpr-context. Now suddenly compiling this program with a different standard library will break your.
So long story short, we need to wait until P1944 has been accepted into the standard
Pretty sure I follow, seems to me though bizarrely what's not constexpr is more "strengthened" conceptually, because what would be saying is I may only be used at runtime, which is a strange restriction to have since at runtime we have less information about what we're dealing with. It's a bit of a tripup for mathematical functions. I mean that I expect std::pow() to be constexpr offhand and get reminded it's not when calling it. Really hope that paper gets through then.
The problem lies with the standard not marking those functions as constexpr which is why a paper is needed. Implementations aren't allowed to apply constexpr where the standard does not mark it as such (if they could then doing so is "strengthening" constexpr for that particular function).
The reason why implementations aren't allowed to strengthen constexpr is because it would make code non-portable, Say you wanted to use std::pow as a template argument. If standard libraries where allowed to make functions constexpr as they saw fit then my usage of it as a template argument may or may not work based on which standard library I use.
Right, but at a certain point the fact that math functions which would be a sensible thing to have constexpr aren't constexpr is very strange whether it's part of the standard specification or not. It almost seems like you guys deserve a [[non-standard]] attribute just to mark code you expect the standard to catch up with.
Although these functions could be considered pure and otherwise perfectly fine to be used at compile time.
Remember that functions like sqrt, tan, and pow are stateful by virtue of being floating point functions. They use global state to transmit errors, via <cfenv> or <cerrno> or both (depending on the implementation, check the value of math_errhandling to know).
So to make them constexpr would require to change this behavior (constexpr is strictly pure), which is obviously a non-starter. You'd effectively need a new set of C++-only functions for this.
That I'll definitely say got lost in translation, that's what I meant by considered pure. Eyeballing the functions you wouldn't necessarily know that's happening, presumably if floating point errors at compile time were that serious you might also be doing some sanity checking of the floating points at compile time, and that'd preclude you from also even looking at that state. I'm fairly certain we're safe assuming if we can't write to global state and can't read global state that could just be ignored....
Constexpr functions aren't pure by any definition of the word I'm familiar with. They can contain almost any amount of code that read or writes global state (including writing to std::cout and reading from std::cin), just as long as that code isn't executed during the evaluation of a constant expression and even as part of a constant expressio they can read an write through pointers.
https://godbolt.org/z/sPT3ar
I think the main reason the math functions aren't constexpr is because they often come from the c standard library on some platforms (I think msvc has intrinsics for most of them).
I'm not entirely sure the entire specification of everything in the math headers, but I'm fairly certain he's worried about the use of c globals which wouldn't work in a constexpr context. Something like from here:
https://en.cppreference.com/w/cpp/numeric/math/pow
I think the point is the error checking wouldn't work because a global is being touched. Eg:
https://godbolt.org/z/vh9ocY
That fails to compile, but I think since globals aren't something we can mess with anyway at compile time it's not particularly important unless you absolutely need the cppreference example to work. Presumably if we are able to check if we're in a compile time context and implement compile time versions of these functions, we're also unable to report errors in that way, and vice versa, we can't read from it either. I wouldn't think it's something that would create an issue.
I think the main reason the math functions aren't constexpr is because they often come from the c standard library on some platforms (I think msvc has intrinsics for most of them).
That definitely seems to be part of it, my sense is that it doesn't often come up as an issue. It probably comes to bite people in the rare case they do try to use them in a constexpr context and everyone's probably skirting around with their own work arounds.
I think the point is the error checking wouldn't work because a global is being touched.
Yes, but as long as there isn't an error to be handled, that state doesn't have to be accessed. You can first check in a constexpr way, if there is a nan or whatever invalid value involved at all and only then got to the if/switch that checks what error mode is active. Anyway, I just wanted to throw in my 5 ct about constexpr implying pure which is a common misconception.
Right, yeah that's kind of where I'm at, and also since that's c's error checking mechanism and it can't be constexpr it's kind of mute point. I really don't see why these can't be made constexpr. I mean when I spotted is_constant_evaluated() it immediately struck me as a way to work around that issue, and apparently I wasn't the first one to think of using it that way so yeah. My 5 cents would be kind of the general sense we're looking at what appear to be pure mathematical functions, seems off they aren't constexpr.
c's error checking mechanism and it can't be constexpr
@Andersama , there is a proposal for C standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2522.pdf
I really dream that they will accept the standard in this form, then C and C ++ will be much closer, and there will be constexpr in C
@miscco's first comment was indeed accurate - the implementation isn't allowed to add constexpr when it doesn't appear in the Standard, so a WG21 proposal would need to be written and accepted in order to do this. (There are additional logistical issues for MSVC with requesting CRT changes, but that's moot unless and until a proposal is voted in.)