# QVM: Quaternions, Vectors, Matrices

### SFINAE/enable_if

SFINAE stands for Substitution Failure Is Not An Error. This refers to a situation in C++ where an invalid substitution of template parameters (including when those parameters are deduced implicitly as a result of an unqualified call) is not in itself an error.

In absence of concepts support, SFINAE can be used to disable function template overloads that would otherwise present a signature that is too generic. More formally, this is supported by the Boost enable_if library.

For example, Boost QVM defines operator* overload which works with any user-defined matrix and vector types. The naive approach would be to declare this overload as follows:

    template <class Matrix,class Vector>
    Vector operator*( Matrix const & m, Vector const & v );

Even if the function definition might contain code that would compile only for Matrix and Vector types, because the function declaration itself is valid, it will participate in overload rezolutions when multiplying objects of any two types whatsoever. This typically renders overload resolutions ambiguous and the compiler (correctly) issues an error.

Using enable_if, Boost QVM declares such overloads in a way that they retain their generic signature but only participate (in overload resolutions) if the passed parameters make sense depending on the semantics of the operation being defined:

    template <class A,class B>
    typename enable_if_c<
        is_mat<A>::value && is_vec<B>::value && mat_traits<A>::cols==vec_traits<B>::dim, //Condition
        B>::type //Return type
    operator*( A const & a, B const & b );

For brevity, function declarations throughout this documentation specify the condition which controls whether they are enabled or not without specifying exactly what enable_if construct is used to achieve this effect.

See also: Accessing Matrix Elements | Accessing Quaternion Elements | Accessing Vector Elements | assign(mat,mat) | assign(quat,quat) | assign(vec,vec) | Boost QVM | boost/qvm/enable_if.hpp | boost/qvm/swizzle.hpp | cmp(mat,mat) | cmp(quat,quat) | cmp(vec,vec) | col | col_mat | conjugate | convert_to(mat) | convert_to(quat) | convert_to(vec) | cross | determinant | diag | diag_mat | dot(quat,quat) | dot(vec,vec) | enable_if | inverse(mat) | inverse(quat) | mag(quat) | mag(vec) | mag_sqr(quat) | mag_sqr(vec) | mref | normalize(quat) | normalize(vec) | normalized(quat) | normalized(vec) | operator!=(mat,mat) | operator!=(quat,quat) | operator!=(vec,vec) | operator*(mat,mat) | operator*(mat,scalar) | operator*(mat,vec) | operator*(quat,quat) | operator*(quat,scalar) | operator*(quat,vec) | operator*(scalar,mat) | operator*(scalar,vec) | operator*(vec,mat) | operator*(vec,scalar) | operator*=(mat,mat) | operator*=(mat,scalar) | operator*=(quat,quat) | operator*=(quat,scalar) | operator*=(vec,scalar) | operator+(mat,mat) | operator+(quat,quat) | operator+(vec,vec) | operator+=(mat,mat) | operator+=(quat,quat) | operator+=(vec,vec) | operator-(mat) | operator-(mat,mat) | operator-(quat) | operator-(quat,quat) | operator-(vec) | operator-(vec,vec) | operator-=(mat,mat) | operator-=(quat,quat) | operator-=(vec,vec) | operator/(mat,scalar) | operator/(quat,scalar) | operator/(vec,scalar) | operator/=(mat,scalar) | operator/=(quat,scalar) | operator/=(vec,scalar) | operator==(mat,mat) | operator==(quat,quat) | operator==(vec,vec) | qref | qvm | rot_mat | rot_quat | rotate(mat,vec,scalar) | rotate(quat,vec,scalar) | rotate_x(mat,scalar) | rotate_x(quat,scalar) | rotate_y(mat,scalar) | rotate_y(quat,scalar) | rotate_z(mat,scalar) | rotate_z(quat,scalar) | row | row_mat | scalar_cast(mat) | scalar_cast(quat) | scalar_cast(vec) | set_identity(mat) | set_identity(quat) | set_rot(mat,vec,scalar) | set_rot(quat,vec,scalar) | set_rotx(mat,scalar) | set_rotx(quat,scalar) | set_roty(mat,scalar) | set_roty(quat,scalar) | set_rotz(mat,scalar) | set_rotz(quat,scalar) | set_zero(mat) | set_zero(quat) | set_zero(vec) | sfinae | slerp | transform_point | transform_vector | translation | translation_mat | vref