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
Related
I was playing around with constexpr in C++ and noticed a strange behavior that I wish to understand. Consider this code from 5.19 section of Standard.
constexpr int f1(int k) {
constexpr int x = k; // error: x is not initialized by a
// constant expression because lifetime of k
// began outside the initializer of x
return x;
}
As error states, lifetime of k began outside the initializer of x, thus we can't be sure that x will be a constant expression.
And here the another version of the same function.
constexpr int f1(int k) {
return k;
}
This one is totally fine and usable. So question is why, here also, the lifetime of k began outside of initializer of return value, or not, or this is because of RVO and technically if just follow the Standard this also should be an error?
And also another question, from which this one actually arise. I was trying to write constexpr IPv4 class. For that purpose I've used constructor with std::string_view. So I was able to have this in compile time using gcc 10.3 and -std=c++20
constexpr IPv4 myIP{"192.168.0.0"};
constexpr size_t count = myIP.countOfDots(); // calls std::count which is constexpr in C++20
Now I want to validate that IP is correct, so I need to check count of dots to be equal to 3, which I can easily do here by
if constexpr (count != 3)
The question is how to organize this into some function, which will also allow me to do such a check in compile time for any given IP, basically I want something like this
constexpr bool validateIP(const IPv4& ip);
And as in the example above, I can't just have this in that function
constexpr size_t count = ip.countOfDots();
So is it possible to do the way I want?
A function that's constexpr means that the function potentially can be evaluated at compile-time. The function must however also be callable with a run-time value, and produce a run-time result.
A variable that's constexpr has to be a compile time constant. Period.
What that means for your validateIP function is that you don't need to make count constexpr. You can write a function and mark it as constexpr.
When you call the function with a compile time constant, it will get evaluated at compile time.
If you call it with a run time value it will get evaluated at run time.
#include <string_view>
#include <iostream>
constexpr bool validateIP(const std::string_view& ip) {
int count = 0;
for (auto& c : ip) {
if (c == '.') {
++count;
}
}
return count == 3;
}
int main()
{
// Assigning the value to a constexpr is not needed to make the function
// be evaluated at compile time, but it proves that it is in this case
constexpr auto isValid1 = validateIP("123.456.789.0");
std::cout << isValid1;
}
I'm currently getting into more C++11 stuff and jumped about constexpr. In one of my books it's said that you should use it for constants like π for example in this way:
#include <cmath>
// (...)
constexpr double PI = atan(1) * 4;
Now I wanted to put that in an own namespace, eg. MathC:
// config.h
#include <cmath>
namespace MathC {
constexpr double PI = atan(1) * 4;
// further declarations here
}
...but here IntelliSense says function call must have a constant value in a constant expression.
When I declare PI the following way, it works:
static const double PI = atan(1) * 4;
What is the actual reason the compiler doesn't seem to like constexpr but static const here? Shouldn't constexpr be eligible here, too, or is it all about the context here and constexprshouldn't be declared outside of functions?
Thank you.
What is the actual reason the compiler doesn't seem to like constexpr but static const here?
A constexpr must be evaluatable at compile time while static const does not need to be.
static const double PI = atan(1) * 4;
simply tells the compiler that PI may not be modified once it is initialized but it may be initialized at run time.
I want to convert a non constant variable to constant variable. I tried using const_cast but still the following program is giving error that ‘bitsize1’ cannot appear in a constant-expression. What am i doing wrong ?
#include <string>
#include <bitset>
#include <iostream>
using namespace std;
int main(){
int l = 3; // taken input from user
int bitsize2 = (l * 2);
int bitsize1 = const_cast<int&>(bitsize2);
string temp = "100101";
bitset<const_cast<int&>(bitsize2)> baz (temp);
cout << baz;
return 0;
}
const_cast is used to cast const away not to make something const. If you want constant expression the easiest way in post-C++11 programming is to use constexpr:
constexpr int l = 3;
constexpr int bitsize2 = l * 2;
The input from user cannot be a compile time constant expression so you must figure out something else.
Templates are expanded in compile time, this means that all template arguments should be known when compiling. Obviously user input is runtime data thus cannot be used as a template argument.
As stated by others, you cannot deduce template parameters at runtime.
You should look into using boost's dynamic bitset.
It exists for the exact problem that you have run into.
"The dynamic_bitset class is nearly identical to the std::bitset class.
The difference is that the size of the dynamic_bitset (the number of
bits) is specified at run-time during the construction of a
dynamic_bitset object, whereas the size of a std::bitset is specified
at compile-time through an integer template parameter."
After answering using boost math constants in constexpr and suggesting OP use boost's templated function for a constexpr variable instead of the non-templated constant to quell a clang error, I decided to try to see what conditions would reproduce the error in clang. Let's try to copy what boost's macro expands to:
namespace double_constants{ static const double name = 25; }
static constexpr double SEC3 = double_constants::name;
This gives the following errors (follow along on Coliru)
clang++ -std=c++1y -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:5:25: error: constexpr variable 'SEC3' must be initialized by a constant expression
static constexpr double SEC3 = double_constants::name;
^ ~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:32: note: read of non-constexpr variable 'name' is not allowed in a constant expression
static constexpr double SEC3 = double_constants::name;
^
main.cpp:3:49: note: declared here
namespace double_constants{ static const double name = 25; }
That's fine, we expected that. Now change double to int:
namespace double_constants{ static const int name = 25; }
static constexpr double SEC3 = double_constants::name;
No error? Needless to say I am confused. I assumed the error was because the variable is defined as const instead of constexpr, unless I'm missing something. Let's take a look at cppreference:
A constexpr variable must satisfy the following requirements:
it must be immediately constructed or assigned a value.
the constructor parameters or the value to be assigned must contain only literal values, constexpr variables and functions.
If we were to interpret this literally, then clang is justified in giving an error because name is only const, not constexpr. And apparently double is a LiteralType because:
std::cout << std::is_literal_type<double>::value;
outputs 1. So why does clang cease to complain if name is int and not a double?
P.S.: Cannot reproduce on gcc.
For clarification, the static keyword is orthogonal to the issue. So is the namespace. From what I understand, the boost macro does not wrap the static const variable in a class, but in a namespace. I've narrowed it down to these four cases:
// Does not compile
const double name = 25;
constexpr int SEC3 = name;
const double name = 25;
constexpr double SEC3 = name;
// Compiles
const int name = 25;
constexpr double SEC3 = name;
const int name = 25;
constexpr int SEC3 = name;
I can't possibly be bothered to apply static in every permutation possible to see if it makes a difference, but I doubt it does.
It's not a bug. Unfortunately the C++ standard has different static/non-static const rules for floating point types and integer types. Please see:
Why aren't static const floats allowed?
Try constexpr instead of const as in:
namespace double_constants{ constexpr double name = 25; }
and:
constexpr double name = 25;
constexpr int SEC3 = name;
Then it should work.
Is there a difference between the following definitions?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
If not, which style is preferred in C++11?
I believe there is a difference. Let's rename them so that we can talk about them more easily:
const double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;
Both PI1 and PI2 are constant, meaning you can not modify them. However only PI2 is a compile-time constant. It shall be initialized at compile time. PI1 may be initialized at compile time or run time. Furthermore, only PI2 can be used in a context that requires a compile-time constant. For example:
constexpr double PI3 = PI1; // error
but:
constexpr double PI3 = PI2; // ok
and:
static_assert(PI1 == 3.141592653589793, ""); // error
but:
static_assert(PI2 == 3.141592653589793, ""); // ok
As to which you should use? Use whichever meets your needs. Do you want to ensure that you have a compile time constant that can be used in contexts where a compile-time constant is required? Do you want to be able to initialize it with a computation done at run time? Etc.
No difference here, but it matters when you have a type that has a constructor.
struct S {
constexpr S(int);
};
const S s0(0);
constexpr S s1(1);
s0 is a constant, but it does not promise to be initialized at compile-time. s1 is marked constexpr, so it is a constant and, because S's constructor is also marked constexpr, it will be initialized at compile-time.
Mostly this matters when initialization at runtime would be time-consuming and you want to push that work off onto the compiler, where it's also time-consuming, but doesn't slow down execution time of the compiled program
constexpr indicates a value that's constant and known during compilation.
const indicates a value that's only constant; it's not compulsory to know during compilation.
int sz;
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation
std::array<int, sz> data1; // error! same problem
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr
Note that const doesn’t offer the same guarantee as constexpr, because const
objects need not be initialized with values known during compilation.
int sz;
const auto arraySize = sz; // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation
All constexpr objects are const, but not all const objects are constexpr.
If you want compilers to guarantee that a variable has a value that can be
used in contexts requiring compile-time constants, the tool to reach for is constexpr, not const.
A constexpr symbolic constant must be given a value that is known at compile time.
For example:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
constexpr int c2 = n+7; // Error: we don’t know the value of c2
// ...
}
To handle cases where the value of a “variable” that is initialized with a value that is not known at compile time but never changes after initialization,
C++ offers a second form of constant (a const).
For Example:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
const int c2 = n+7; // OK, but don’t try to change the value of c2
// ...
c2 = 7; // error: c2 is a const
}
Such “const variables” are very common for two reasons:
C++98 did not have constexpr, so people used const.
List item “Variables” that are not constant expressions (their value is not known at compile time) but do not change values after
initialization are in themselves widely useful.
Reference : "Programming: Principles and Practice Using C++" by Stroustrup
One more example to understand the difference between const and constexp.
int main()
{
int n;
cin >> n;
const int c = n; // OK: 'c' can also be initialized at run time
constexpr int e = n; // Error: 'e' must be initialized at compile time
}
Note: constexpr normally evaluated at compile-time, but they are not guaranteed to do so unless they're invoked
in a context where a constant expression is required.
constexpr int add(int a, int b)
{
return a + b;
};
int main()
{
int n = add(4, 3); // may or may not be computed at compile time
constexpr int m = add(4,3); // must be computed at compile time
}
constexpr -> Used for compile time constant. This is basically used for run time optimization.
const -> Used for run time constant.