Edited again because it originally wasn't clear that I'm trying to initialize the arrays at compile time, not at run time...
I've got the following reduced testcase:
typedef struct TestStruct
{
int length;
int values[];
};
TestStruct t = {3, {0, 1, 2}};
TestStruct t2 = {4, {0, 1, 2, 3}};
int main()
{
return(0);
}
This works with Visual C++, but doesn't compile with g++ under linux. Can anyone help me make this specific kind of initializer portable?
Additional details: the actual structure I'm working with has several other int values, and the array can range in length from a single entry to over 1800 entries.
EDIT: I think (but am not sure) that this is not a VLA issue. To clarify, I'm trying to get the compiler to do the work for me at compile-time. The length of the array at run-time is constant. Apologies if I'm wrong; I'm primarily a c#/Perl/Ruby programmer who is stuck maintaining this legacy app...
Any help much appreciated. Thanks!
c++ doesn't have the same flexible array member as last element as c99. You should use a std::vector
if you don't know how many elements or you should specify how many if you do.
EDIT: You have said in your edit that the array is a runtime constant, so specify the size and it should work fine. g++ has no problem with the following code:
struct TestStruct { // note typedef is not needed */
int length;
int values[3]; // specified the size
};
TestStruct t = {3, {0, 1, 2}};
int main() {
// main implicitly returns 0 if none specified
}
EDIT: to address your comment, you could use templates like this:
template <int N>
struct TestStruct {
int length;
int values[N];
};
TestStruct<3> t3 = {3, {0, 1, 2}};
TestStruct<2> t2 = {2, {0, 1}};
int main() {}
The only problem is that there is no easy way to put both t2 and t3 in a container (like a list/vector/stack/queue/etc because they have different sizes. If you want that, you should use std::vector
. Also, if you are doing that, then it isn't necessary to store the size (it is associated with the type). So you could do this instead:
template <int N>
struct TestStruct {
static const int length = N;
int values[N];
};
TestStruct<3> t3 = {{0, 1, 2}};
TestStruct<2> t2 = {{0, 1}};
int main() {}
But once again, you cannot put t2 and t3 in a "collection" together easily.
EDIT: All in all, it sounds like you (unless you store more data than just some numbers and the size) don't need a struct at all, and can't just use a plain old vector.
typedef std::vector<int> TestStruct;
int t2_init[] = { 0, 1, 2 };
TestStruct t3(t3_init, t3_init + 3);
int t2_init[] = { 0, 1 };
TestStruct t2(t2_init, t2_init + 2);
int main() {}
Which would allow you to have both t2 and t3 in a collection together. Unfortunately std::vector
doesn't (yet) have array style initializer syntax, so i've used a shortcut. But it's simple enough to write a function to populate the vectors in a nice fashion.
EDIT: OK, so you don't need a collection, but you need to pass it to a function, you can use templates for that to preserve type safety!
template <int N>
struct TestStruct {
static const int length = N;
int values[N];
};
TestStruct<3> t3 = {{0, 1, 2}};
TestStruct<2> t2 = {{0, 1}};
template <int N>
void func(const TestStruct<N> &ts) { /* you could make it non-const if you need it to modify the ts */
for(int i = 0; i < N; ++i) { /* we could also use ts.length instead of N here */
std::cout << ts.values[i] << std::endl;
}
}
// this will work too...
template <class T>
void func2(const T &ts) {
for(int i = 0; i < ts.length; ++i) {
std::cout << ts.values[i] << std::endl;
}
}
int main() {
func(t2);
func(t3);
func2(t2);
}