An important design goal of Boost QVM is that it works seamlessly with 3rd-party quaternion, vector and matrix types and libraries. Even when such libraries overload the same C++ operators as Boost QVM, it is safe to bring the entire boost::qvm namespace in scope by specifying:
using namespace boost::qvm;
The above using directive does not introduce ambiguities with function and operator overloads a 3rd-party library may define because:
Bringing the boost::qvm namespace in scope lets you mix vector and matrix types that come from different APIs into a common, type-safe framework. In this case however, it should be considered what types should be returned by binary operations that return an object by value. For example, if you multiply a 3x3 matrix m1 of type user_matrix1 by a 3x3 matrix m2 of type user_matrix2, what type should that operation return?
The answer is that by default, Boost QVM returns some kind of compatible matrix type, so it is always safe to write:
auto & m = m1 * m2;
However, the type deduced by default converts implicitly to any compatible matrix type, so the following is also valid, at the cost of a temporary:
user_matrix1 m = m1 * m2;
While the temporary object can be optimized away by many compilers, it can be avoided altogether by specializing the deduce_mat2 template. For example, to specify that multiplying a user_matrix1 by a user_matrix2 should always produce a user_matrix1 object, you could specify:
namespace boost { namespace qvm { template <> struct deduce_mat2<user_matrix1,user_matrix2,3,3> { typedef user_matrix1 type; }; template <> struct deduce_mat2<user_matrix2,user_matrix1,3,3> { typedef user_matrix1 type; }; } }
Finally, any time you need to create a matrix of a particular C++ type from any other compatible matrix type, you can use the convert_to function:
user_matrix2 m=convert_to<user_matrix2>(m1 * m2);
Perhaps surprisingly, unary operations that return an object by value have a similar, though simpler issue. That's because the argument they're called with may not be copyable, as in:
float m[3][3];
auto & inv = inverse(m);
Again, Boost QVM "just works", returning an object of suitable matrix type that is copyable. This deduction process can also be controlled, by specializing the deduce_mat template.
Note: Bringing the entire boost::qvm namespace in scope may introduce ambiguities when accessing types (as opposed to functions) defined in 3rd-party libraries. In that case, you can safely bring namespace boost::qvm::sfinae in scope instead, which contains only function and operator overloads that use SFINAE/enable_if.
Warning: Be mindful of potential ODR violation when using deduce_quat2, deduce_vec2 and deduce_mat2 in 3rd party libraries. For example this could happen if lib1 defines deduce_vec2<lib1::vec,lib2::vec>::type as lib1::vec and in the same program lib2 defines deduce_vec2<lib1::vec,lib2::vec>::type as lib2::vec. It is best to keep such specializations out of lib1 and lib2. Of course, it is always safe for lib1 and lib2 to use convert_to to convert between the lib1::vec and lib2::vec types as needed.
Tutorial navigation: Quaternions, Vectors, Matrices | C Arrays | Views | Swizzling | Interoperability
See also: Boost QVM