I have a simple class template for 3D vectors:
template <typename T>
struct Vec3
{
T x, y, z; // vector components
...
}
where the template parameter T
can be int
, float
or double
(for now anyway). I have two requirements when overloading the division operator:
I came up with this short implementation:
template <typename = std::enable_if_t<std::is_floating_point_v<T>>>
Vec3 operator/(T a) const
{
assert(a != 0);
T inva = static_cast<T>(1.0)/a;
return Vec3{inva*x, inva*y, inva*z};
}
A few questions regarding this piece of code:
Is it worth using a variable template for the constant 1.0
? Will the compiler be smart enough to do the static_cast at compile time? C++ static_cast runtime overhead
template<typename T>
constexpr T one = T(1.0);
EDIT: gcc didn't mind, but clang wouldn't compile the code above. This is because my usage of SFINAE is incorrect. A correct implementation would be
template <typename U = T,
typename = std::enable_if_t<std::is_floating_point_v<U>>>
Vec3 operator/(T a) const
{
...
}
more details can be found here: std::enable_if to conditionally compile a member function
- Is there another non-SFINAE way to restrict this member function to floating point types? (I am using C++17)
overloads as free functions (as std::is_floating_point_v
is true only for few types (float
, double
, long double
(+ cv_variant)))
Vec3<float> operator / (const Vec3<float>& vec, float value) {/*..*/}
Vec3<double> operator / (const Vec3<float>& vec, float value) {/*..*/}
Vec3<long double> operator / (const Vec3<float>& vec, float value) {/*..*/}
SFINAE seems the better alternative.
C++20 would introduce requires
to discard those methods cleanly:
Vec3 operator/(T a) const requires(std::is_floating_point_v<T>) {/*..*/}
- Are modern compilers smart enough to compute the division first and then perform three multiplications? Is it a waste of time and expressiveness to do that myself?
With floating point, result might differs, so compiler won't do that (unless it can ensure it would result in same result).
- Is it worth using a variable template for the constant 1.0? Will the compiler be smart enough to do the static_cast at compile time?
I will trust compiler to replace the code static_cast<float>(1.0)
by 1.f
.