* Merged constExpressions() into other test cases, reducing duplicates
and simplifying the checks.
* Fixed old-and-forgotten operator[] overload in Matrix subclasses, it
was reinterpret_cast on T* array, it is now sufficient to do only
static_cast. Constexpr operator[] overload returns const copy to make
constexpr operations working even on returned value, e.g.:
constexpr Matrix4 a;
constexpr Vector3 b = a[2].xyz();
Also updated all dependent classes to follow the change, such as Color
and Rectangle. Backwards compatibility for GCC 4.6 (with lack of support
for delegating constructors) will be done as non-constexpr constructor
using operator=().
Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.
On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:
Matrix<2, int> a(1, 2, // before
3, 4);
Matrix<2, int> a(Vector<2, int>(1, 2), // now
Vector<2, int>(3, 4));
For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:
Matrix<3, int>({1, 2, 3},
{4, 5, 6},
{7, 8, 9});
I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.
Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076.
Removed workarounds for alias templates, variadic templates and
anonymous enums, but 1.8.2 has some bug with forward declarations
causing classes to appear in default namespace, breaking
cross-references.
It prevents unwanted implicit conversions from e.g. nullptr to Camera,
Vector2 to Physics::Point etc. By making all the constructors explicit
it is easier to routinely add the keyword to all new classes instead of
thinking about cases when to add and when not to.
Lowecase didn't prove to be better, because Doxygen cannot implicitly
link to it and it collides with non-type template parameters and private
variables.
Loop unrolling is better to leave up to the compiler, as it will do it
automatically and it doesn't add any maintenance burden. Constexpr
addition, multiplication etc. of Vector would be nice, but will that be
really useful? Maybe once if at all?
Now all possible cases are properly handled (row vector * column vector,
column vector * row vector, ...). All operators taking arbitrary type as
argument (element-wise multiplication) now have std::enable_if only for
numerical types.
Currently moved only non-square functionality from Matrix there. Also
static constant members such as row/column count and size are now
lowercase, as they are variables, not types.
NumericType is corresponding numeric type with size at least the same as
int. It is used in debug operators for Matrix and Vector to prevent
printing chars as characters.
If the type isn't already floating-point, FloatingPointType is
corresponding larger type with sufficient size for normalization of
given integral type.
Also updated type traits for long types, they are now subclassed either
from int or long long based on sizeof(long).
On the other hand everything of this is done at runtime, so it's less
performant than the previous version, mainly when used in loops. When
the result is declared as constexpr, it is done at compile time, just
like the previous version.
I don't know which version to keep, so there will be both until a good
decision.
Doxygen produces some false-positive warnings for Matrix and Vector
classes, but the generated documentation is fine. Worked around the
warnings by using @copybrief and @copydetails instead of @copydoc.
C++ allows creating arrays with initializer lists shorter than array
length, but for vectors and matrices it will be error prone and hard to
debug. Removed deleted constructor, as it is now catched with
static_assert as well. Also this was possible before (and wasn't catched
with the deleted constructor), now isn't:
Matrix<2, int> a(1, 2);
Each function which returned e.g. Vector<size, T> was in subclasses
overloaded with function returning e.g. Vector3<T>, so the user is able
to use subclass-specific functions. It was nightmare to maintain and it
cluttered the documentation a lot.
Long-standing TODO. It is better to have size first, because it is more
significant than type (e.g. because there are Vector4<T> specializations
and not VectorT<4> specializations). It is also IMHO easier for user to
distinguish/read the type than before:
Vector<float, 4> -> Vector4<float> // before
Vector<4, float> -> Vector4<float> // now
GCC does some heavy magic optimizations in -O2 (-O1 works) and it
somewhat breaks them. It should be safe to use them outside of Matrix,
though (e.g. when not used in loops through all elements).