Shallow copies aren't important to me, and after years of using C++ templates and C# generics I've come to quite like having the type where I can see it!
As for why I didn't use this approach in general, a couple of reasons:
- I often have arrays of pointers. Now you need a second parameter, to give the struct its name...
- You need to decide in advance all the possible array types you're going to have, and keep the list up to date. I wanted this to feel a lot more like using std::vector
- You can't redeclare a struct, even with the same declaration. So if you have MAKE_ARRAY_T(int) in one header, because your object has an array of int, and MAKE_ARRAY_T(int) in another, because ditto, you can't include both headers from the same file. So again you need to be able to give the type a name
- Structs can't be mixed and matched as flexibly as variables. So say you've got MAKE_ARRAY_T(int,Module1Ints) in the header for module 1 and MAKE_ARRAY_T(int,Module2Ints) in the header for module 2 - both are arrays of ints, and you avoid the naming problems I described above. But now you can't use one in place of the other, even when this would make sense
It also doesn't help with passing your arrays into your generic array functions, since you don't have a single type that you can pass around. So you're restricted to passing in the 3 individiual pieces, or inlining snippest of code via macro, like mine does.
Something I did try in the past was using anonymous structs:
#define ARRAY(T) struct { T *p; size_t len, cap; }
However, anonymous structs are always different, even if they're structurally equivalent, so... no go. (I also dimly remember Visual Studio not even being able to show you the struct in the debugger!) But I guess trying that out was probably a stepping stone on the way to my thinking of the code I've put here.
> It also doesn't help with passing your arrays into your generic array functions, since you don't have a single type that you can pass around. So you're restricted to passing in the 3 individiual pieces, or inlining snippest of code via macro, like mine does.
When I did something like this, the type definition macro also defined strongly typed implementations of all the array functions for the given type T. Then a call is a real function call and is only inlined if the compiler chooses to do it.
The other points you mention were not problems in the particular application I was working on, but yes, these are interesting trade-offs.
As for why I didn't use this approach in general, a couple of reasons:
- I often have arrays of pointers. Now you need a second parameter, to give the struct its name...
- You need to decide in advance all the possible array types you're going to have, and keep the list up to date. I wanted this to feel a lot more like using std::vector
- You can't redeclare a struct, even with the same declaration. So if you have MAKE_ARRAY_T(int) in one header, because your object has an array of int, and MAKE_ARRAY_T(int) in another, because ditto, you can't include both headers from the same file. So again you need to be able to give the type a name
- Structs can't be mixed and matched as flexibly as variables. So say you've got MAKE_ARRAY_T(int,Module1Ints) in the header for module 1 and MAKE_ARRAY_T(int,Module2Ints) in the header for module 2 - both are arrays of ints, and you avoid the naming problems I described above. But now you can't use one in place of the other, even when this would make sense
It also doesn't help with passing your arrays into your generic array functions, since you don't have a single type that you can pass around. So you're restricted to passing in the 3 individiual pieces, or inlining snippest of code via macro, like mine does.
Something I did try in the past was using anonymous structs:
However, anonymous structs are always different, even if they're structurally equivalent, so... no go. (I also dimly remember Visual Studio not even being able to show you the struct in the debugger!) But I guess trying that out was probably a stepping stone on the way to my thinking of the code I've put here.