But there is a problem about implementing those functions, namely the support of mathematical operations for certain types. For example, the norm (length) of a vector requires the square root to be defined for the type. What should Norm(IntVector) return? The same applies for the UnitVector (as it divides a vector by its norm).
I propose, an angle function should be added as well, which tells us about the direction of a vector. The vector [1, 0] corresponds to 0°, [0, 1] would be 90° and so on. But here, the problem again comes up because the required function atan2() to compute the angle isn't supported for all types. I wouldn't force the user to provide a set of functions named sqrt, atan2 and so on. Remember, sqrt and atan2 are actually in namespace std and according to the C++ standard, programmers may not extend std except for template specializations. So, you don't know which namespace to use.
Instead, I suggest the solution about traits. Traits are class templates, which define some types, static functions or constants, and which can be specialized for every type. This could look like:
// General, empty template
template <typename T>
struct TrigonometricTraits
{
typedef T Type;
};
// template specialization for built-in float
template <>
struct TrigonometricTraits<float>
{
typedef float Type;
static Type Atan2(Type ValY, Type ValX) { return std::atan2(ValY, ValX); }
static Type Sqrt(Type Value) { return std::sqrt(Value); }
};
Perhaps, a trait could also support functions to transform between degree and radians, here for float:
static Type RadToDegFactor() { return 180.f / 3.14159265f; }
static Type DegToRadFactor() { return 3.14159265f / 180.f; }
For example, if one uses boost::rational<int> as vector type, the transformation factors must be represented as fractions. The user can now specialize the TrigonometricTraits template for his own types in order to make them work with the vector functions.
A vector function might be implemented like the following:
template <typename T>
T Angle(const sf::Vector2<T>& Vector)
{
return ToDegree<T>(TrigonometricTraits<T>::Atan2(Vector.y, Vector.x));
}
Where ToDegree() is the mentioned transformation function:
template <typename T>
T ToDegree(T Radian)
{
return Radian * TrigonometricTraits<T>::RadToDegFactor();
}
This may look scaring, but such an implementation is highly generic and flexible. For types which don't support the operations in a useful way (like int), the template is not specialized, resulting in a compile time error.
What do you think about this solution?