Declaring array with const and constexpr [duplicate] - c++

This question already has an answer here:
Can an array be declared with a size that is a const variable not a constexpr?
(1 answer)
Closed 2 years ago.
While investigating the constexpr keyword in C++, I've come up with the following code:
#include <iostream>
int main() {
const int n = 10;
constexpr int n2 = 10;
int a1[n];
int a2[n2];
std::cout << "n " << n << std::endl;
std::cout << "n2 " << n2 << std::endl;
}
I would expect that declaring the array a1 with "const" would not work and the compiler would at least give me a warning (assuming the compilation is done with g++ -Wall -pedantic constexpr_1.cpp -o ce1) but it does not. I've seen some error with VS compiler so any hint is welcome here.

In C++, the size of each array dimension in an array declaration must be an integral constant expression.
A constant expression (with some exceptions) is a value that can be evaluated at compile-time. That includes const variables with automatic storage duration initialized by a constant expression [ref].
Therefore both const int n = 10; and constexpr int n2 = 10; are usable as a size in array declarations and the code example is valid.
Note: this is not the case in C - so make sure to compile in C++ mode [ref].
The code also compiles fine in MSVC 2015+. But it could very well be that an archaic VC++ compiler has a bug that prevents this from compiling.

Related

Weird type assignment for array index in C++

Hi I have a sample program
#include <iostream>
int main() {
int a = -5;
int arr[a];
std::cout << "Size of arr: " << sizeof(arr) << std::endl;
return 0;
}
Here I am getting the output of 17179869164.
My question is that the array size value should not accept negative values! and if I try giving a[-5], it throws an error. but now how am I getting the output of 17179869164.
I have my assumption too, the -5 is converted to an unsigned int value of 4294967291 and the total size is given as 17179869164 = 4294967291 * 4(size of int).
So I wanted to know why the compiler is typecasting signed int to unsigned int and not throwing a compile-time error. I needed a clear understanding of how the compiler is executing that piece of code?
It is something called undefined behavior. To catch that kind of bug you could use the help of a static analyser.
Someone else asked something similar here:
Declaring an array of negative length
For C++, Variable Length Arrays are not provide by the standard, but may be provided by compiler extension. For C, the short answer is the standard converts the value to a positive integer value unless it is a constant expression -- in your case resulting in the use of the unsigned value (use of the two's compliment value as a positive value). Specifically:
C11 Standard - 6.7.6.2 Array
declarators(p5)
If the size is an expression that is not an integer constant
expression: if it occurs in a declaration at function prototype scope,
it is treated as if it were replaced by *; otherwise, each time it is
evaluated it shall have a value greater than zero.
I noticed some interesting behavior in GodBolt.
I took you code and added a second copy where a is declared constant:
#include <iostream>
int foo() {
int a = -5;
int arr[a];
std::cout << "Size of arr: " << sizeof(arr) << std::endl;
return 0;
}
int bar() {
const int a = -5;
int arr[a];
std::cout << "Size of arr: " << sizeof(arr) << std::endl;
return 0;
}
Then I threw GCC, Clang, and MSVC at them.
As far as I know, GCC and Clang both support variable length arrays (VLAs) as an "extra feature", and they both ate foo without a single complaint. Whereas MSVC, who does not support VLAs, complained.
On the other hand, none of them accepted bar on account of a being negative.
As for why GCC and Clang can't tell that ais negative in foo, that I will leave as a question for people more versed in compiler guts than I.

Initializing constexpr with const: Different treatment for int and double [duplicate]

This question already has answers here:
Constant expression initializer for static class member of type double
(2 answers)
Closed 2 years ago.
The following code fails to compile live on Ideone:
#include <iostream>
using namespace std;
int main() {
const double kPi = 3.14;
constexpr double kPi2 = 2.0*kPi;
cout << kPi2;
}
The error message is:
prog.cpp: In function 'int main()':
prog.cpp:6:30: error: the value of 'kPi' is not usable in a constant expression
constexpr double kPi2 = 2.0*kPi;
^
prog.cpp:5:15: note: 'kPi' was not declared 'constexpr'
const double kPi = 3.14;
Substituting the const declaration for kPi with constexpr, it compiles successfully.
On the other hand, when int is used instead of double, seems like const plays well with constexpr:
#include <iostream>
using namespace std;
int main() {
const int k1 = 10;
constexpr int k2 = 2*k1;
cout << k2 << '\n';
return 0;
}
Why do int and double get different treatments for initializing a constexpr with const?
Is this a bug in the Ideone compiler? Is this required by the C++ standard? Why is that?
Was the above code UB?
P.S. I tried with Visual Studio 2015 C++ compiler, and it compiles the first code snippet (initializing constexpr with const) just fine.
Shafik Yaghmour already provided a link explaining the background.
Since I have to maintain code which has to compile with different standards, I use the following macro:
#if __cplusplus <= 199711L // lower than C++11
#define MY_CONST const
#else // C++11 and above
#define MY_CONST constexpr
#endif
The for a constexpr to be calculated at compile time everything that is used in the initialization of that constexpr also must be calculatable at compile time.
If you declare something as const it does not mean that the value will be available at compile time.
Take the following line:
const double dbl = 2.;
The double's representation is not specified by the standard so the OS will have to deal with this. So when your program is loaded by the OS there is a special assembly subroutine in your binary that will make this happen.
If you use an int the representation is specified by the standard so the compiler will know how to work with it. However the same can be achieved by making the double a constexpr as well, so the compiler will compute it in compile time. In this case the double will also be a const (you cannot make something constexpr without also making it const).
So this will work:
constexpr double kPi = 3.14;
constexpr double kPi2 = 2.0*kPi;
If you use an int the compiler will set the value of that const at compile time so the constexpr will work.
Keep in mind that different compilers can interpret const as constexpr in some cases and make it work. But that is not part of the standard.
Rule:"constexpr must be evaluate at compile time".
Let's look below code (generic example);
const double k1 = size_of_array();
k1 is constant, the value of its initializer is not known compile time but its initializer is known until run time so k1 is not constant expression. As a result a const variable is not constexpr.
But compiler see these code:
const int k1 = 10;
constexpr int k2 = 2*k1;
One exception occurs. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations [1].
You can get extra information from the links below:
Constexpr - Generalized Constant Expressions in C++11
const vs constexpr on variables | stackoverflow
Difference between constexpr and const | stackoverflow

Defining arrays with(out) constant expressions

I am slowly bringing myself up to c++11. I was looking at constexpr and stumbled into this wikipedia article which lead me to "something completely different". The basic example it gives is:
int get_five() {return 5;}
int some_value[get_five() + 7]; // Create an array of 12 integers. Ill-formed C++
It states "This was not legal in C++03, because get_five() + 7 is not a constant expression." and says that adding constexpr to the get_five() declaration solves the problem.
My question is "What problem?". I compiled that code with neither errors nor warnings. I played with it making it horribly non constant:
#include <iostream>
int size(int x) { return x; }
int main()
{
int v[size(5) + 5];
std::cout << sizeof(v) + 2 << std::endl;
}
This compiles with no complaints using:
g++ -Wall -std=c++03
and when executed I get the (correct) answer 42.
I admit that I generally use stl containers, not arrays. But I thought (and apparently so did wikipedia) that compilation of the above code would fail miserably. Why did it succeed?
Variable-length arrays (that is, arrays whose size is determined by a non-constant expression) are allowed in C, and some C++ compilers allow them as an extension to the language. GCC is one such compiler.
You'll get a warning if you compile with -pedantic or -Wvla, or an error with -pedantic-errors. Use those flags if you want to avoid non-standard compiler extensions.
As it has been said already some C++ compilers support C feature named Variable Length Array(s) whose sizes can be specified at run-time.
However VLA(s) may not be declared with static storage duration. The program you showed
#include <iostream>
int size(int x) { return x; }
int main()
{
int v[size(5) + 5];
std::cout << sizeof(v) + 2 << std::endl;
return 0;
}
can be compiled. However if you place the array outside any function then the code will not be compiled. Consider the following program that is similar to your original program with minor changes.
#include <iostream>
int size(int x) { return x; }
int v[size(5) + 5];
int main()
{
std::cout << sizeof(v) + 2 << std::endl;
return 0;
}
In this case the compiler will issue an error. However if you will specify constexpr for function size then the above program will be compiled successfully
#include <iostream>
constexpr int size(int x) { return x; }
int v[size(5) + 5];
int main()
{
std::cout << sizeof(v) + 2 << std::endl;
return 0;
}
The C++ Standard requires that sizes of arrays would be constant expressions.
8.3.4 Arrays [dcl.array]
1 In a declaration T D where D has the form
D1 [ constant-expressionopt] attribute-specifier-seqopt
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is an array type;
Take into acount that not all C++ compilers (and even C compilers; for C compilers it is implementation defined whether a compiler supports VLA) have such a language extension as VLA. So if you want that your program would be C++ compliant then you should not rely on specific language extensions of a compiler.
Some compilers have extensions, which implement VLA (Variable Length Arrays).
Compile with -pedantic and you'll see the difference.

Can C++ constexpr function actually accept non-constant expression as argument?

I have defined a constexpr function as following:
constexpr int foo(int i)
{
return i*2;
}
And this is what in the main function:
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
The program was compiled under OS X 10.8 with command clang++. I was surprised that the compiler did not produce any error message about foo(i) not being a constant expression, and the compiled program actually worked fine. Why?
The definition of constexpr functions in C++ is such that the function is guaranteed to be able to produce a constant expression when called such that only constant expressions are used in the evaluation. Whether the evaluation happens during compile-time or at run-time if the result isn't use in a constexpr isn't specified, though (see also this answer). When passing non-constant expressions to a constexpr you may not get a constant expression.
Your above code should, however, not compile because i is not a constant expression which is clearly used by foo() to produce a result and it is then used as an array dimension. It seems clang implements C-style variable length arrays as it produces the following warning for me:
warning: variable length arrays are a C99 feature [-Wvla-extension]
A better test to see if something is, indeed, a constant expression is to use it to initialize the value of a constexpr, e.g.:
constexpr int j = foo(i);
I used the code at the top (with "using namespace std;" added in) and had no errors when compiling using "g++ -std=c++11 code.cc" (see below for a references that qualifies this code) Here is the code and output:
#include <iostream>
using namespace std;
constexpr int foo(int i)
{
return i*2;
}
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
output:
4
0 1 2 3
Now consider reference https://msdn.microsoft.com/en-us/library/dn956974.aspx It states: "...A constexpr function is one whose return value can be computed at compile when consuming code requires it. A constexpr function must accept and return only literal types. When its arguments are constexpr values, and consuming code requires the return value at compile time, for example to initialize a constexpr variable or provide a non-type template argument, it produces a compile-time constant. When called with non-constexpr arguments, or when its value is not required at compile-time, it produces a value at run time like a regular function. (This dual behavior saves you from having to write constexpr and non-constexpr versions of the same function.)"
It gives as valid example:
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}
This is an old question, but it's the first result on a google search for the VS error message "constexpr function return is non-constant". And while it doesn't help my situation, I thought I'd put my two cents in...
While Dietmar gives a good explanation of constexpr, and although the error should be caught straight away (as it is with the -pedantic flag) - this code looks like its suffering from some compiler optimization.
The value i is being set to 2, and for the duration of the program i never changes. The compiler probably noticed this and optimized the variable to be a constant (just replacing all references to variable i to the constant 2... before applying that parameter to the function), thus creating a constexpr call to foo().
I bet if you looked at the disassembly you'd see that calls to foo(i) were replaced with the constant value 4 - since that is the only possible return value for a call to this function during execution of the program.
Using the -pedantic flag forces the compiler to analyze the program from the strictest point of view (probably done before any optimizations) and thus catches the error.

constexpr function not calculate value in compile time

I want to compare meta programming and use of constexpr in c++0x.
then I write a fib function in both model.
when I use meta programming model, answer print out very fast because it calculated in compile time. but when I use constexpr funcion it calculate value in run time, not in compile time.
I using g++( gcc ) 4.8 .can any body help me?
#include <iostream>
using namespace std;
#define NUM 42
template <unsigned int N>
struct Fibonacci {
enum { value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value };
};
template <>
struct Fibonacci<1> {
enum { value = 1 };
};
template <>
struct Fibonacci<0> {
enum { value = 1 };
};
constexpr unsigned int fib(unsigned int n)
{
return (n > 1 ? fib(n-1) + fib(n-2) : 1 );
}
int main()
{
cout << "Meta_fib(NUM) : " << Fibonacci<NUM>::value << endl; // compile time :)
cout << "Constexpr_fib(NUM) : " << fib(NUM) << endl; // run time :-?
return 0;
}
I believe the reason is that constexpr is not guaranteed to execute at compile-time. To enforce compile-time evaluation, you have to assign it to a compile-time alias. Like,
enum {i = fib(NUM)};
With gcc, at least, you can get the constexpr value to be computed at compile time by making it a static variable:
static const unsigned fibNUM = fib(NUM);
As I read the standard, it's still allowed to compute the value at startup, but in practice it will be computed at compile time.
A simple test to see if your constexpr are really being done at compile-time is to use an std::array:
#include <array>
std::array<int, Fibonacci<5>::value> arr;
std::array<int, fib(5)> arr2;
gcc has no complaints.
See this comment by Bjarne Stroustrup:
... according to the standard a constexpr function may be evaluated at
compiler time or run time unless it is used as a constant expression,
in which case it must be evaluated at compile-time. To guarantee
compile-time evaluation, we must either use it where a constant
expression is required (e.g., as an array bound or as a case label) or
use it to initialize a constexpr. I would hope that no self-respecting
compiler would miss the optimization opportunity to do what I
originally said: "A constexpr function is evaluated at compile time if
all its arguments are constant expressions."
constexpr is not guaranteed to be evaluated at compile time. This means, compiler can choose whether to evaluate at compile time or at run time.
You can try to assign it to a compile time constant and check like this...
const long i = fib(NUM);// here i should be initialized at the time of
// declaration
cout << "Meta_fib(NUM) : " << Fibonacci<NUM>::value << endl;
cout << "Constexpr_fib(NUM) : " << i << endl;