A vector wrapper is useful if used as an adapter between vectors from different libraries. It removes the need to explicitly construct a vector of type B when you have a vector of type A.
It's roughly equivalent to using a reinterpret_cast on your vectors, but the code tries really hard to make sure the cast is valid in all cases, wrapping safety checks nicely behind a clean interface. Implicit constructors also allow to convert easily from one type to the other (if enabled at build time).
We all need vectors in our code, and there are quite a few implementations out there. They all do their job, and in terms of interface they are pretty similar to each other, but not *exactly* the same thing.
While this is not an issue in its own, it can become a problem when your code depends on external libraries that will provide their own vector implementation. So you might have your own implementation, MyVector, and the library will give you Ogre::Vector3, which is what you must use when you invoke Ogre's functions. If you also depend on openCV you will have yet another vector around. Microsoft Kinect SDK also imposes you its own, barebone vector implementation.
While through discipline you can manage such cases more or less well, there is one major issue that I couldn't work around: your own library code. I like to write code I think I will re-use at some point in the future in libraries separate from the main program. Odds are at some point you will need some maths that are not covered by the library vector you are using. Unless it's something really particular, I will probably try to write it in some library so that other projects can benefit from my new formula. The good thing about low level libraries is that they have very few dependencies, or none at all, and can thus be carried around and adapted to a variety of projects. It's all nice and good, but how would you add your new function taking a Ogre::Vector3 into a library that depends on nothing without bringing in the whole Ogre3D library?
So what's the real benefit of using `Vec<Ogre::Vector3>` instead of just `Ogre::Vector3`, for example? Can't I just assign/cast manually?
Sure you can, but it's more verbose. And as your codebase grows, you will have more and more boundaries where you have to convert from one vector to the other just to call a function from this or that library. Check test/unit/example.cpp for a head-to-head comparison of the two methods.
The basic idea is that all vectors will somehow give you access to some x, y, z coordinates. You will do that very frequently in your code, maybe on different platforms and in time critical parts of your code, so virtual calls (or equivalent) are not an option. This library is entirely templated, and will let you wrap any type inside a Vec. In fact, you could even just use this wrapper as your vector of choice, using an `std::array<float, 3>` as the wrapped type and forget how it's working under the hood.
Unfortunately the fact that you use `Vec<std::array<float, 3>>` and `Vec<Ogre::Vector3>` also means that you still have several types of vectors in your program. The good news is that conversion is automated (no more `Ogre::Vector3(other_vec.X, other_vec.Y, other_vec.Z)` in your code) and often it will not even be necessary, as casting will suffice.
You still need to type some code in order to get started using the vector wrapper class, which is basically your custom implementation of a struct listing informations about the wrapped type. That's not a lot of code.
* VWR_WITH_IMPLICIT_CONVERSIONS (default: not defined) Enable implicit conversions between wrappers of vectors of different type (see Automated conversions).
You can assign or construct a `Vec<A>` from a `Vec<B>`, provided they have the same dimensions and the assignemnt operator is able to convert B's scalar type to that of A. You need to define VWR_WITH_IMPLICIT_CONVERSIONS for this to work.
You can convert one vector to the other using vector_cast. For example, auto b = vector_cast<float2>(a); will create a temporary of type float2 the whose elements are a static_cast'ed copy of the elements in a and assign it to b. You need to include vectorwrapper/vector_cast.hpp.
Through the `data()` method you can always obtain a ref to the wrapped type.
### Dimension change ###
Depending on the wrapped type, Vec can provide methods to get a Vec of lower or higher dimensions. For example, `Vec<Ogre::Vector3>` can optionally expose a `xy()` method that is equivalent to `Vec<Ogre::Vector2>(vec3.x(), vec3.y())`.
A must have some fundamental properties before it can be casted to B:
* casting won't result in a misaligned object
* the casted object won't go past the memory reserved to the original object (in other words sizeof(B) <= sizeof(A) - offset of the first coordinate in A)
* B must be a standard layout struct
* B has no data before the first coordinate
* Coordinates in B appear in the same order and at the same offsets as they appear in A
* B is exactly as large as dimensions * sizeof(scalar_type), but you can disable this constraint by setting cast_ignore_trailing_properties=1 in B's VectorWrapperInfo
Vectors must still have the same dimensions. `cast<type>()` is only available when you define `offset_x` (see <u>Usage</u>). Either way, to cast (reinterpret_cast actually, be careful about the strict aliasing rule) you can just do the following:
typedef Vec<A> avec;
typedef Vec<B> bvec;
avec a(0);
some_function(bvec(a)); //creates a temporary
some_function(a.cast<bvec>()); //reinterpret_cast
## Usage ##
In this example we will adapt `std::array<float, N>` and `Ogre::VectorN`. In your real code, write the VectorWrapperInfo specializations for your own wrapped types in some header file, and just include it in your code to use Vec with those types.
* [ ] Read-only vectors are not supported (not sure if such a thing is really needed)
* [ ] I haven't profiled this code yet (please be patient), but while I don't want it to slow your program down, I know it won't be comparable to any super optimized vector library. This is not a vector library to begin with. Supporting SSE would be nice, but there is no guarantee the wrapped type has been created with SSE and optimizations in mind. Writing functions for both cases (SIMD-ready structures and scalar structures) would essentially require implementing every function twice. I think it's just a better idea to take an already made vector library and use vectorwrapper as it was intended - to wrap the vector classes that come from that library.