Why isn't abs constexpr? - c++

In <cinttypes>, since C++11, there are the following two overloads:
std::intmax_t abs( std::intmax_t n );
std::intmax_t imaxabs( std::intmax_t n );
Why aren't those two functions constexpr?

I can't give a good reason for why abs couldn't be constexpr and apparently neither can gcc. When I use gcc 4.9.2 with this program:
#include <cstdlib>
#include <cinttypes>
#include <cassert>
constexpr intmax_t abs3 = std::abs(3);
constexpr intmax_t absneg3 = std::abs(-3);
int main()
{
assert(abs3 == absneg3);
}
it compiles and runs to completion with no warnings or errors. You can try it here. However, clang++ (version 3.5.0) throws a compile-time error:
abs.cpp:6:20: error: constexpr variable 'abs3' must be initialized by a constant expression.
I think that clang++ actually gets it right here, because in section 27.9.2 [c.files] of the 2011 standard, it says:
The contents of header are the same as the Standard C Library header , with the following changes:
— the header includes the header instead of , and
— if and only if the type intmax_t designates an extended integer type (3.9.1), the following function
signatures are added:
intmax_t abs(intmax_t);
imaxdiv_t div(intmax_t, intmax_t);
which shall have the same semantics as the function signatures intmax_t imaxabs(intmax_t) and
imaxdiv_t imaxdiv(intmax_t, intmax_t), respectively.
In the current working draft of the C++ standard, as in the published 2014 version, it says in section 17.6.5.6 [constexpr.functions]:
This standard explicitly requires that certain standard library functions are constexpr (7.1.5). An implementation shall not declare any standard library function signature as constexpr except for those where it
is explicitly required.
So the result, for now, is that these functions are still not constexpr according to the standard (which you knew) but they could be, as demonstrated by the gcc compiler.

It has been proposed in P0533:
A function in <cmath> shall be declared
constexpr if and only if:
When taken to act on the set of rational numbers,
the function is closed (excluding division by zero);
The function does not modify any of its arguments
which have external visibility;
The function is not strongly dependent on the
rounding mode.
By means of a brief illustration, abs satisfies all three criteria; however, functions such as exp, sqrt, cos, sin fall foul of the first criterion and so are excluded as constexpr candidates. Finally, as discussed above, nearbyint fails the final criterion.

The simple explanation is probably that nobody went through every function listed as part of the standard library, and updated the entry to make it constexpr.
Updating a standard is a process involving human effort to propose changes and get those proposals reviewed and accepted. And that means, when a new feature is added - and constexpr is a new feature - not everything else is automagically updated to use that feature. This particular case may well be updated in a future evolution of the standard - if some people take on the - often thankless - task of proposing the set of changes, some other people take on the task of reviewing it, and convincing those with voting power on the committee to accept it.

It is constexpr since C++23
long abs( long n ); (2) (constexpr since C++23)
https://en.cppreference.com/w/cpp/numeric/math/abs

Related

MSVC 2015 cannot compile constexpr atan

I have used Mingw-w64 compiler in my project. Now I am compiling the project with MSVC2015. The following line gives an error:
constexpr double pi = 4*std::atan(1);
error:
error: C2131: expression did not evaluate to a constant
However it compiled in mingw without any problems.
MSVC is right in this case, from [constexpr.functions]p1
This document explicitly requires that certain standard library functions are constexpr. An implementation shall not declare any standard library function signature as constexpr except for those where it is explicitly required.
As you can see from the last sentence that I highlighted, an implementation is not allowed to declare a function constexpr if the standard doesn't say so.
Now does the standard say that atan is constexpr? No, as can be seen from the signature in [c.math]:
float atan(float x); // see [library.c]
double atan(double x);

Purpose of constexpr

This is more of a philosophical question rather than practical code snippet, but perhaps C++ gurus can enlighten me (and apologies if it's been asked already).
I have been reading Item 15 in Meyers's "Effective Modern C++" book, as well as this thread: implicit constexpr? (plus a reasonable amount of googling). The item goes over usage of constexpr for expressions, namely that it defines functions that can return compile time values given compile time inputs.
Moreover, the StackOverflow thread I referred to shows that some compilers are perfectly capable of figuring out for themselves which function invocation results are known at compile time.
Hence the question: why was constexpr added to the standard as compared to defining when compilers should derive and allow static/compile-time values?
I realise it makes various compile-only (e.g. std::array<T, constexpr>) definitions less predictable, but on the other hand, as per Meyers's book, constexpr is a part of the interface,..., if you remove it, you may cause arbitrarily large amounts of client code to stop compiling.
So, not only having explicit constexpr requires people to remember adding it, it also adds permanent semantics to the interface.
Clarification: This question is not about why constexpr should be used. I appreciate that having an ability to programatically derive compile-time values is very useful, and employed it myself on a number of occasions. It's a question on why it is mandatory in situations where compiler may deduce const-time behaviour on its own.
Clarification no. 2: Here is a code snippet showing that compilers do not deduce that automatically, I've used g++ in this case.
#include <array>
size_t test()
{
return 42;
}
int main()
{
auto i = test();
std::array<int, i> arrayTst;
arrayTst[1] = 20;
return arrayTst[1];
}
std::array declaration fails to compile because I have not defined test() as constexpr, which is of course as per standard. If the standard were different, nothing would have prevented gcc from figuring out independently that test() always returns a constant expression.
This question does not ask "what the standard defines", but rather "why the standard is the way it is"?
Before constexpr the compilers could sometimes figure out a compile time constant and use it. However, the programmer could never know when this would happen.
Afterwards, the programmer is immediately informed if an expression is not a compile time constant and he or she realizes the need to fix it.

Is it a conforming compiler extension to treat non-constexpr standard library functions as constexpr?

gcc compiles the following code without warning:
#include <cmath>
struct foo {
static constexpr double a = std::cos(3.);
static constexpr double c = std::exp(3.);
static constexpr double d = std::log(3.);
static constexpr double e1 = std::asin(1.);
static constexpr double h = std::sqrt(.1);
static constexpr double p = std::pow(1.3,-0.75);
};
int main()
{
}
None of the standard library functions used above are constexpr functions, we are allowed to use them where a constant expression is required from both the draft C++11 standard and draft C++14 standard section 7.1.5 [dcl.constexpr]:
[...]If it is initialized by a constructor call, that call shall be a
constant expression (5.19). Otherwise, or if a constexpr specifier is
used in a reference declaration, every full expression that appears in
its initializer shall be a constant expression.[...]
Even when using -std=c++14 -pedantic or -std=c++11 -pedantic no warnings are generated (see it live). Using -fno-builtin produces errors (see it live) which indicates that the builtin version of these standard library functions are being treated as if they where constexpr
While clang does not allow the code with any combination of flags I have tried.
So this is a gcc extension to treat at least some builtin functions as if they were constexpr functions even though the standard does not explicitly require them to be. I would have expected to at least receive a warning in strict conformance mode, is this a conforming extension?
TL;DR
In C++14 this is explicitly not allowed, although in 2011 it appeared like this case would be explicitly allowed. It is unclear if for C++11 this fell under the as-if rule, I don't believe it does since it alters observable behavior but that point was not clarified in the issue I reference below.
Details
The answer to this question has shifted with the evolving status of LWG issue 2013 which opens with:
Suppose that a particular function is not tagged as constexpr in the
standard, but that, in some particular implementation, it is possible
to write it within the constexpr constraints. If an implementer tags
such a function as constexpr, is that a violation of the standard or
is it a conforming extension?
In C++11 it was unclear if the as-if rule permitted this but the orignal proposal would have explicitly allowed it once it was accepted and we can see below in the gcc bug report I reference, this was the assumption made by the gcc team.
The consensus to allow this shifted in 2012 and the proposal changed and in C++14 this is a non-conforming extension. This is reflected in the draft C++14 standard section 17.6.5.6 [constexpr.functions] which says:
[...]An implementation shall not declare any standard library function
signature as constexpr except for those where it is explicitly
required.[..]
and although a strict reading of this seems to leave some wiggle room for treating a builtin implicitly as if it were a constexpr we can see from the following quote in the issue that the intention was to prevent divergence in implementations since identical code could produce different behavior when using SFINAE (emphasis mine):
Some concern expressed when presented to full committee for the vote
to WP status that this issue had been resolved without sufficient
thought of the consequences for diverging library implementations, as
users may use SFINAE to observe different behavior from otherwise
identical code.
We can see from the gcc bug report [C++0x] sinh vs asinh vs constexpr that the team relied on the earlier proposed resolution of LWG 2013 which says:
[...]Additionally, an implementation may declare any function to be
constexpr if that function's definition satisfies the necessary
constraints[...]
when deciding whether this change for the math functions was allowed in strict conformance mode.
As far as I can tell this would become conforming if this we received a warning in strict conformance mode i.e. using -std=c++11 -pedantic or if it was disabled in this mode.
Note, I added a comment to the bug report explaining that the resolution changed since this issue was originally addressed.
Jonathan Wakely pointed out in another question a more recent discussion and it seems likely the gcc bug report will be reopened to address this conformance issue.
What about intrinsics
Compiler intrinsics are not covered by the standard and so as far as I can tell they should be exempt from this rule, so using:
static constexpr double a = __builtin_cos(3.);
should be allowed. This question came up in the bug report and opinion of Daniel Krügler was:
[...]Library functions and other intrinsics can probably be considered as
exceptions, because they are not required to be "explainable" by
normal language rules.

implicit constexpr?

Can C++11 compilers (and do they) notice that a function is a constexpr and treat them as such even if they are not declared to be constexpr?
I was demonstrating the use of constexpr to someone using the example straight from the Wikipedia:
int get_five() {return 5;}
int some_value[get_five() + 7]; // Create an array of 12 integers. Ill-formed C++
To my surprise the compiler was OK with it. So, I further changed get_five( ) to take a few int parameters, multiply them and return the result while still not being explicitly declared to be constexpr. The compiler was OK with that as well. It seems that if the compiler can do this there isn't much point to having the restrictions that are required in order to explicitly declare something constexpr.
On a properly-functioning C++11 compiler, your code would be rejected.
Based on its being accepted, you're almost certainly using gcc (or something that closely emulates its bugs). gcc [depending somewhat on flags] can accept array sizes that aren't constant by any measure (e.g., depend on run-time input from the user) because they support an analog of C99 variable-length arrays in C++.
GCC, as of GCC 12, supports the -fimplicit-constexpr command-line toggle which enables exactly that, for methods marked as inline.
Changelog: https://gcc.gnu.org/gcc-12/changes.html
Patch with some rationale and discussion: https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=87c2080b
A compiler can detect whether or not a function could have been declared with constexpr even when they haven't, for optimization purposes (i.e. computing the result of a function at compile-time). Compilers did that prior to C++11.
But for use in places that requires constant expressions, such as template parameters of integral type, it is against the standard to allow calls to functions that are not declared with the constexpr keyword.

const problem in VS2010

I have the shortest question possible:
Why does this not work in VS2010?
string keyword("lookuptable");
const int kwSize = keyword.size();
char oldBuffer[kwSize+1];
It works perfectly in GCC. VS2010 tells me that
"expression must have constant value"
I am using Win32 console application / empty project.
I am using absolutely nothing special, just
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
using namespace std
and its a single main function in a cpp file.
The size of an array must be an integral constant expression, or ICE (which means that it must be known at compile-time). You can use a const int in an ICE, but only if its initializer is itself an ICE.
A function call, like keyword.size() is not usable in an ICE, so kwSize is not usable in an ICE.
If it "works perfectly" in gcc it is either due to a bug or a language extension of some sort.
In C++0x, some function calls can be used in integral constant expressions, but they must be constexpr functions and there are restrictions on their use. To the best of my knowledge, no compiler fully supports constexpr yet. In any case, std::string::size is not constexpr.
GCC has a language extension allowing variable-length arrays. Visual C++ does not. You must initialize stack-based arrays with a fixed, compile-time constant.
As others have mentioned, non-constant array bounds are a GCC extension (likely a side benefit of its C99 support - C99 does allow non-constant array bounds). If you want this in C++, you should use a vector:
std::vector oldBuffer(kwSize + 1);
To turn this into a char *, do:
&oldBuffer[0]
This, while not strictly speaking valid C++ prior to C++0x, works properly in every compiler I've come across so far. C++0x retroactively blesses this usage, and also provides a oldBuffer.data() equivalent.
the answer is there "expression must have constant value". The const has to be something resolved at the compile time.
keyword.size() is evaluated at runtime therefore it is not a compile time constant. Depending on the compiler it may not be allowed to use an array size that is depending on some runtime value.
Some further info about variable array length in gcc