So I've been quite busy with refactoring the rendering and other systems of the engine for the last few months, and once I'm done I'll make some more entries for the graphical render-system.
Today I've been wondering if there is no cleaner solution to having to pass an arbitrary array to a function. I generally tend to fully qualify the container in such a case, but thats not always possible (and quite frankly not the flexible). What I'm talking about is a case like that:DrawItem* Compile(const StateGroup* pGroups, size_t numGroups);{ for(size_t i = 0; i < numGroups; i++) // no range-based for loops eigther :( { }}
Having to pass in the pointer and size separately to the function seems unsafe, C-esque and redundant to me. Not being able to use range-based for-loops is a minor annoyance. But there is no other native way, if I potentially want to support any source of array (raw fixed-size array, std::vector, std::array, dynamic allocation, ...).
So I came up with what I call an ArrayView-class. What it does and how it works is actually quite simple, which makes me wonder why I havn't seen anybody else come up with something like that:DrawItem* Compile(ArrayView groups){ for(const auto& group : groups) { }}
Yeah, thats the gist of it. I'm using a templated class to pass a view to an array, with a known size. The cool thing is, now it doesn't matter where this array comes from:void printArray(ArrayView view){ for(const int value : view) { std::cout << value; } std::cout << std::endl << std::endl;}void main(void){ std::vector vector = {1, 2, 3, 4, 5}; std::array array = { 1, 2, 3, 4, 5 }; int raw[] = { 1, 2, 3, 4, 5 }; int* pDynamic = new int[5] { 1, 2, 3, 4, 5}; const auto vectorView = makeArrayView(vector); const auto arrayView = makeArrayView(array); const auto rawView = makeArrayView(raw); const auto iteratorView = makeArrayView(vector.begin() + 2, vector.begin() + 4); const auto pointerView = makeArrayView(raw + 1, raw + 3); const auto dynamicView = makeArrayView(pDynamic, 5); const ArrayView* views[] = { &vectorView, &arrayView, &rawView, &iteratorView, &pointerView, &dynamicView, }; for(const auto pView : views) { printArray(*pView); } }
You can construct it from std::vector, std::array, compile-time arrays, even random-access iterators (probably a tad unsafe), and a raw-range of pointers (even more unsafe, but meh).
________________________________________________________
So... any reasons nobody has come up with something like that yet? Is the problem I'm trying to solve so uncommon/unimportant that nobody cared? Or are people still wary of using templates?
For me, I think I've spent my ~hour to write this quite well, as this will probably kill my conditioning to just put "vector" everywhere, even when I could just pass in a regular array. :D
For those of you interested in using this or trying it out, I've attached the header-file, alongside a visual-studio natvis-file. Requires C++11 (VS2015 or higher), and you'll have to replace the AE_ASSERTS with your own assert-macro, if you use one. This is the first iteration just after writing it, so there's probably still lots of stuff missing, but I consider it useable :)
This is pretty neat, it is in C++ GSL btw.
Otherwise this is what i do for ranged for loops when there are no iterators:
https://gist.github.com/ongamex/0ecf47bd5eff4044b0cc26db20c86102
the usage is