3D 向量的高效除法运算符
Efficient division operator for 3D vectors
我有一个简单的 class 3D 矢量模板:
template <typename T>
struct Vec3
{
T x, y, z; // vector components
...
}
其中模板参数 T
可以是 int
、float
或 double
(目前无论如何)。重载除法运算符时我有两个要求:
- 它必须尽可能高效。
- 它必须仅适用于浮点类型
我想到了这个简短的实现:
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};
}
关于这段代码的几个问题:
- 是否有另一种非 SFINAE 方法来限制此成员函数浮动
点类型? (我正在使用 C++17)
- 现代编译器是否足够聪明,可以先计算除法,然后
然后执行三次乘法?是不是浪费时间
和表现力自己做?
是否值得为常数1.0
使用变量模板?编译器是否足够聪明,可以在编译时执行 static_cast ? C++ static_cast runtime overhead
template<typename T>
constexpr T one = T(1.0);
编辑:gcc 不介意,但 clang 不会编译上面的代码。这是因为我对 SFINAE 的使用不正确。正确的实施方式是
template <typename U = T,
typename = std::enable_if_t<std::is_floating_point_v<U>>>
Vec3 operator/(T a) const
{
...
}
可以在此处找到更多详细信息: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)
- class 的完全或部分专业化(对于部分专业化,需要进行更改以使 class SFINAE 友好)。
重载为自由函数(因为 std::is_floating_point_v
仅适用于少数类型(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 似乎是更好的选择。
C++20 将引入 requires
以彻底丢弃这些方法:
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?
对于浮点数,结果可能不同,因此编译器不会这样做(除非它可以确保它会产生相同的结果)。
- 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?
我相信编译器会将代码 static_cast<float>(1.0)
替换为 1.f
。
我有一个简单的 class 3D 矢量模板:
template <typename T>
struct Vec3
{
T x, y, z; // vector components
...
}
其中模板参数 T
可以是 int
、float
或 double
(目前无论如何)。重载除法运算符时我有两个要求:
- 它必须尽可能高效。
- 它必须仅适用于浮点类型
我想到了这个简短的实现:
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};
}
关于这段代码的几个问题:
- 是否有另一种非 SFINAE 方法来限制此成员函数浮动 点类型? (我正在使用 C++17)
- 现代编译器是否足够聪明,可以先计算除法,然后 然后执行三次乘法?是不是浪费时间 和表现力自己做?
是否值得为常数
1.0
使用变量模板?编译器是否足够聪明,可以在编译时执行 static_cast ? C++ static_cast runtime overheadtemplate<typename T> constexpr T one = T(1.0);
编辑:gcc 不介意,但 clang 不会编译上面的代码。这是因为我对 SFINAE 的使用不正确。正确的实施方式是
template <typename U = T,
typename = std::enable_if_t<std::is_floating_point_v<U>>>
Vec3 operator/(T a) const
{
...
}
可以在此处找到更多详细信息: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)
- class 的完全或部分专业化(对于部分专业化,需要进行更改以使 class SFINAE 友好)。
重载为自由函数(因为
std::is_floating_point_v
仅适用于少数类型(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 似乎是更好的选择。
C++20 将引入 requires
以彻底丢弃这些方法:
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?
对于浮点数,结果可能不同,因此编译器不会这样做(除非它可以确保它会产生相同的结果)。
- 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?
我相信编译器会将代码 static_cast<float>(1.0)
替换为 1.f
。