Reputation: 97
I wrote a simple test program using CGAL, and running into the following issue:
Point is defined above as
typedef K::Point_d Point;
but I don't think this is relevant.
When I attempt to compile the program as follows:
const int size = 10;
Point P[size];
g++ does so without issue.
If instead I attempt to compile:
const int size = stoi("10");
Point P[size]
I get the following error
error: variable length array of non-POD element type 'Point' (aka 'Point_d<Cartesian_d<double,
CGAL::Linear_algebraCd<double, std::__1::allocator<double> > > >')
Why is size considered a variable instead of a const when retrieved from a string?
Upvotes: 4
Views: 714
Reputation: 15144
To expand on kabanus’ answer, the language standard says that an array bound in C++11 must be something called an integral constant expression. C++17 relaxes this slightly and allows a few more things, but that’s not important right now.
This page at cppreference lists all the things you are not allowed to do inside a constant expression. It basically quotes the language standard.
The relevant section that allows your first example is 8a. You are not allowed to use a variable, unless it’s a const
variable initialized to a constant expression. So using the name of a const
variable of integral type that is initialized to a constant expression is legal, as in your first example. Numeric constants are constant expressions, so size
is a const
variable initialized to a constant expression, which is A-OK.
However, due to point 2, function calls are only constant expressions if they are both declared constexpr
and already defined. So, for a standard library function to be usable in an array expression in your code, it would need to be declared constexpr
and also defined in the header file.
The standard does not say that stoi()
qualifies, although I don’t think anything in it directly forbids some implementation from providing that as an extension.
Upvotes: 0
Reputation: 25980
C++ defines specific things to be constant expressions that are defined to be known at compile time - see constant_expression.
In general functions that are not defined as constexpr
are not, regardless of what you pass them. You could try and force it as such:
#include<string>
constexpr int x = std::stoi("10");
int main() {
return 0;
}
but you will find this still leads to an error:
error: call to non-constexpr function 'int std::stoi(const string&, std::size_t*, int)'
so, you are out of luck as stoi
is not a constant expression. If you really insist you could override this using your own implementation for example that in How do I convert a C string to a int at compile time?.
Upvotes: 2
Reputation: 1226
In the first code sample
const int size = 10;
Point P[size];
the particular value of size
can be used already at compile time, since it is known (you've specified it). Therefore the compiler may replace all its uses with particular value, w/o actually creating a variable.
In the second sample
const int size = stoi("10");
Point P[size]
the compiler cannot know the value, since it is deduced by the stoi
function at runtime. Therefore it cannot substitute the size of the array (which must be known beforehand to determine now much memory to allocate), and you get the error.
In C++11 there is constexpr idiom, which allows some functions, declared as constexpr, be evaluated at compile time. But in your case stoi
isn't constexpr function, so you cannot achieve what you want using this particular function. You can implement your own constexpr stoi
, but I don't see much sence in it, since your code in this case would contain somethins like this: my_constexpr_stoi("10")
, i.e. the argument is always manually written and always known beforehand. Why don't write just 10
?..
Upvotes: 1
Reputation: 9355
The first const int size = 10;
is a compile time const expression and it can be computed during compilation,
but const int size = stoi("10")
is not a compile time const expression hence it fails to compile.
std::stoi
is not a constexpr
function to evaluated on compile time.
If you want to have this functionality you may need to create a constexpr
function to evaluate on compile time.
constexpr bool is_digit(char c) {
return c <= '9' && c >= '0';
}
constexpr int stoi_impl(const char* str, int value = 0) {
return *str ?
is_digit(*str) ?
stoi_impl(str + 1, (*str - '0') + value * 10)
: throw "compile-time-error: not a digit"
: value;
}
constexpr int to_int(const char* str) {
return stoi_impl(str);
}
int main() {
constexpr int size = to_int("10");
int arr[size];
}
This will compile; [copied from here]
Upvotes: 1
Reputation: 8284
The compiler doesn't understand the semantics of the stoi
function. All it sees is you calling a function that returns an integer (whether that function can be inlined and optimized away is a seperate issue from the semantics).
To the compiler there is very little semantic difference between
const int size = stoi("10");
and
const int size = getchar();
As other answers mentioned constexpr
being the exception. I just thought I'd illustrate the issue.
Upvotes: 1
Reputation: 11
stoi is not evaluated at compile time. That means the compiler does not know how big the array should be. if you want to do something like that you have to use a constexpr function (constexpr function). These can be evaluated at compile time, then it works.
Upvotes: 1