From 75857541c3d99192b2a5c3d0913d4842b242c076 Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 29 Aug 2025 12:45:44 -0700 Subject: [PATCH] Replace =delete with SFINAE for invalid Vec integer methods The Vec2, Vec3, and Vec4 classes declare methods length(), normalize(), normalizeExc(), normalizeNonNull(), normalized(), normalizedExc(), and normalizedNonNull(), which are invalid for integer types. The pre-existing declarations remove the integer instantiations via `=delete`: template <> IMATH_HOSTDEVICE short Vec2::length () const IMATH_NOEXCEPT = delete; but this appears to not work with Clang20 (at least on msys2, as reported in https://github.com/AcademySoftwareFoundation/openexr/issues/2101). The template appears to get instantiated _before_ the `=delete`, which causes an error. I tried moving the `=delete` to _just_ after the class declaration, but that doesn't appear to resolve the problem. This change replaces the `=delete` with SFINAE (Substitution Failure is Not an Error): template >> IMATH_HOSTDEVICE T length () const IMATH_NOEXCEPT; With this form, the declaration is excluded entirely if the condition fails (i.e. if T is not a floating-point type). Unlike `=delete`, which makes the function ill-formed if called, SFINAE makes the function invisible to the compiler when the condition is not satisfied. Note that this requires C++17. Imath has previously only required C++14. Signed-off-by: Cary Phillips --- .github/workflows/ci_workflow.yml | 12 +- src/Imath/ImathVec.h | 220 +++++++----------------------- 2 files changed, 54 insertions(+), 178 deletions(-) diff --git a/.github/workflows/ci_workflow.yml b/.github/workflows/ci_workflow.yml index 1d1d3a6..497b792 100644 --- a/.github/workflows/ci_workflow.yml +++ b/.github/workflows/ci_workflow.yml @@ -47,7 +47,7 @@ jobs: os: ubuntu-latest build: ${{ matrix.build }} cmake: ${{ matrix.cmake || '3.15.7' }} - cxx-standard: ${{ matrix.cxx-standard || '14' }} + cxx-standard: ${{ matrix.cxx-standard || '17' }} cxx-compiler: ${{ matrix.cxx-compiler || 'g++' }} cc-compiler: ${{ matrix.cc-compiler || 'gcc' }} build-type: ${{ matrix.build-type || 'Release' }} @@ -84,7 +84,7 @@ jobs: python: 'OFF' pybind11: 'OFF' cmake: 3.14.7 - cxx-standard: 14 + cxx-standard: 20 - build: 5 label: custom namespace @@ -108,7 +108,7 @@ jobs: # values. os: ${{ matrix.os || 'macos-15' }} build: ${{ matrix.build }} - cxx-standard: ${{ matrix.cxx-standard || '14' }} + cxx-standard: ${{ matrix.cxx-standard || '17' }} build-type: ${{ matrix.build-type || 'Release' }} python: ${{ matrix.python || 'ON' }} pybind11: ${{ matrix.pybind11 || 'ON' }} @@ -142,7 +142,7 @@ jobs: BUILD_TESTING: 'OFF' python: 'OFF' pybind11: 'OFF' - cxx-standard: 14 + cxx-standard: 20 - build: 5 label: macos-15-intel @@ -168,7 +168,7 @@ jobs: # values. os: ${{ matrix.os || 'windows-2022' }} build: ${{ matrix.build }} - cxx-standard: ${{ matrix.cxx-standard || '14' }} + cxx-standard: ${{ matrix.cxx-standard || '17' }} build-type: ${{ matrix.build-type || 'Release' }} python: ${{ matrix.python || 'ON' }} pybind11: ${{ matrix.pybind11 || 'ON' }} @@ -208,7 +208,7 @@ jobs: BUILD_TESTING: 'OFF' python: 'OFF' pybind11: 'OFF' - cxx-standard: 14 + cxx-standard: 20 - build: 5 label: vfx2023 diff --git a/src/Imath/ImathVec.h b/src/Imath/ImathVec.h index 86e73d8..5d2db50 100644 --- a/src/Imath/ImathVec.h +++ b/src/Imath/ImathVec.h @@ -280,6 +280,7 @@ public: /// @name Query and Manipulation /// Return the Euclidean norm + template >> IMATH_HOSTDEVICE T length () const IMATH_NOEXCEPT; /// Return the square of the Euclidean norm, i.e. the dot product @@ -287,27 +288,33 @@ public: IMATH_HOSTDEVICE constexpr T length2 () const IMATH_NOEXCEPT; /// Normalize in place. If length()==0, return a null vector. + template >> IMATH_HOSTDEVICE const Vec2& normalize () IMATH_NOEXCEPT; /// Normalize in place. If length()==0, throw an exception. + template >> const Vec2& normalizeExc (); /// Normalize without any checks for length()==0. Slightly faster /// than the other normalization routines, but if v.length() is /// 0.0, the result is undefined. + template >> IMATH_HOSTDEVICE const Vec2& normalizeNonNull () IMATH_NOEXCEPT; /// Return a normalized vector. Does not modify *this. + template >> IMATH_HOSTDEVICE Vec2 normalized () const IMATH_NOEXCEPT; /// Return a normalized vector. Does not modify *this. Throw an /// exception if length()==0. + template >> Vec2 normalizedExc () const; /// Return a normalized vector. Does not modify *this, and does /// not check for length()==0. Slightly faster than the other /// normalization routines, but if v.length() is 0.0, the result /// is undefined. + template >> IMATH_HOSTDEVICE Vec2 normalizedNonNull () const IMATH_NOEXCEPT; /// @} @@ -352,6 +359,7 @@ public: typedef T BaseType; private: + template >> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny () const IMATH_NOEXCEPT; }; @@ -612,6 +620,7 @@ public: /// @name Query and Manipulation /// Return the Euclidean norm + template >> IMATH_HOSTDEVICE T length () const IMATH_NOEXCEPT; /// Return the square of the Euclidean norm, i.e. the dot product @@ -619,28 +628,34 @@ public: IMATH_HOSTDEVICE constexpr T length2 () const IMATH_NOEXCEPT; /// Normalize in place. If length()==0, return a null vector. + template >> IMATH_HOSTDEVICE const Vec3& normalize () IMATH_NOEXCEPT; /// Normalize in place. If length()==0, throw an exception. + template >> const Vec3& normalizeExc (); /// Normalize without any checks for length()==0. Slightly faster /// than the other normalization routines, but if v.length() is /// 0.0, the result is undefined. + template >> IMATH_HOSTDEVICE const Vec3& normalizeNonNull () IMATH_NOEXCEPT; /// Return a normalized vector. Does not modify *this. + template >> IMATH_HOSTDEVICE Vec3 normalized () const IMATH_NOEXCEPT; // does not modify *this /// Return a normalized vector. Does not modify *this. Throw an /// exception if length()==0. + template >> Vec3 normalizedExc () const; /// Return a normalized vector. Does not modify *this, and does /// not check for length()==0. Slightly faster than the other /// normalization routines, but if v.length() is 0.0, the result /// is undefined. + template >> IMATH_HOSTDEVICE Vec3 normalizedNonNull () const IMATH_NOEXCEPT; /// @} @@ -685,6 +700,7 @@ public: typedef T BaseType; private: + template >> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny () const IMATH_NOEXCEPT; }; @@ -926,6 +942,7 @@ public: /// @name Query and Manipulation /// Return the Euclidean norm + template >> IMATH_HOSTDEVICE T length () const IMATH_NOEXCEPT; /// Return the square of the Euclidean norm, i.e. the dot product @@ -933,28 +950,34 @@ public: IMATH_HOSTDEVICE constexpr T length2 () const IMATH_NOEXCEPT; /// Normalize in place. If length()==0, return a null vector. + template >> IMATH_HOSTDEVICE const Vec4& normalize () IMATH_NOEXCEPT; // modifies *this /// Normalize in place. If length()==0, throw an exception. + template >> const Vec4& normalizeExc (); /// Normalize without any checks for length()==0. Slightly faster /// than the other normalization routines, but if v.length() is /// 0.0, the result is undefined. + template >> IMATH_HOSTDEVICE const Vec4& normalizeNonNull () IMATH_NOEXCEPT; /// Return a normalized vector. Does not modify *this. + template >> IMATH_HOSTDEVICE Vec4 normalized () const IMATH_NOEXCEPT; // does not modify *this /// Return a normalized vector. Does not modify *this. Throw an /// exception if length()==0. + template >> Vec4 normalizedExc () const; /// Return a normalized vector. Does not modify *this, and does /// not check for length()==0. Slightly faster than the other /// normalization routines, but if v.length() is 0.0, the result /// is undefined. + template >> IMATH_HOSTDEVICE Vec4 normalizedNonNull () const IMATH_NOEXCEPT; /// @} @@ -999,6 +1022,7 @@ public: typedef T BaseType; private: + template >> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny () const IMATH_NOEXCEPT; }; @@ -1084,178 +1108,6 @@ typedef Vec4 V4f; /// Vec4 of double typedef Vec4 V4d; -//---------------------------------------------------------------------------- -// Specializations for VecN, VecN -// -// Normalize and length don't make sense for integer vectors, so disable them. -//---------------------------------------------------------------------------- - -/// @cond Doxygen_Suppress - -// Vec2 -template <> -IMATH_HOSTDEVICE short Vec2::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec2& - Vec2::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec2& Vec2::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec2& - Vec2::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec2 - Vec2::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec2 Vec2::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec2 -Vec2::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec2 -template <> -IMATH_HOSTDEVICE int Vec2::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec2& - Vec2::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec2& Vec2::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec2& - Vec2::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec2 - Vec2::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec2 Vec2::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec2 - Vec2::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec2 -template <> -IMATH_HOSTDEVICE int64_t Vec2::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec2& - Vec2::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec2& Vec2::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec2& -Vec2::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec2 - Vec2::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec2 Vec2::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec2 -Vec2::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec3 -template <> -IMATH_HOSTDEVICE short Vec3::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec3& - Vec3::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec3& Vec3::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec3& - Vec3::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec3 - Vec3::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec3 Vec3::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec3 -Vec3::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec3 -template <> -IMATH_HOSTDEVICE int Vec3::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec3& - Vec3::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec3& Vec3::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec3& - Vec3::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec3 - Vec3::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec3 Vec3::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec3 - Vec3::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec3 -template <> -IMATH_HOSTDEVICE int64_t Vec3::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec3& - Vec3::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec3& Vec3::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec3& -Vec3::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec3 - Vec3::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec3 Vec3::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec3 -Vec3::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec4 -template <> -IMATH_HOSTDEVICE short Vec4::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec4& - Vec4::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec4& Vec4::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec4& - Vec4::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec4 - Vec4::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec4 Vec4::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec4 -Vec4::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec4 -template <> -IMATH_HOSTDEVICE int Vec4::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec4& - Vec4::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec4& Vec4::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec4& - Vec4::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec4 - Vec4::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec4 Vec4::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec4 - Vec4::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -// Vec4 -template <> -IMATH_HOSTDEVICE int64_t Vec4::length () const IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE const Vec4& - Vec4::normalize () IMATH_NOEXCEPT = delete; -template <> const Vec4& Vec4::normalizeExc () = delete; -template <> -IMATH_HOSTDEVICE const Vec4& -Vec4::normalizeNonNull () IMATH_NOEXCEPT = delete; -template <> -IMATH_HOSTDEVICE Vec4 - Vec4::normalized () const IMATH_NOEXCEPT = delete; -template <> Vec4 Vec4::normalizedExc () const = delete; -template <> -IMATH_HOSTDEVICE Vec4 -Vec4::normalizedNonNull () const IMATH_NOEXCEPT = delete; - -/// @endcond Doxygen_Suppress - //------------------------ // Implementation of Vec2: //------------------------ @@ -1554,6 +1406,7 @@ Vec2::operator/ (T a) const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T Vec2::lengthTiny () const IMATH_NOEXCEPT { @@ -1579,6 +1432,7 @@ Vec2::lengthTiny () const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline T Vec2::length () const IMATH_NOEXCEPT { @@ -1598,6 +1452,7 @@ Vec2::length2 () const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline const Vec2& Vec2::normalize () IMATH_NOEXCEPT { @@ -1619,6 +1474,7 @@ Vec2::normalize () IMATH_NOEXCEPT } template +template inline const Vec2& Vec2::normalizeExc () { @@ -1633,6 +1489,7 @@ Vec2::normalizeExc () } template +template IMATH_HOSTDEVICE inline const Vec2& Vec2::normalizeNonNull () IMATH_NOEXCEPT { @@ -1643,6 +1500,7 @@ Vec2::normalizeNonNull () IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline Vec2 Vec2::normalized () const IMATH_NOEXCEPT { @@ -1654,6 +1512,7 @@ Vec2::normalized () const IMATH_NOEXCEPT } template +template inline Vec2 Vec2::normalizedExc () const { @@ -1666,6 +1525,7 @@ Vec2::normalizedExc () const } template +template IMATH_HOSTDEVICE inline Vec2 Vec2::normalizedNonNull () const IMATH_NOEXCEPT { @@ -2031,6 +1891,7 @@ Vec3::operator/ (T a) const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T Vec3::lengthTiny () const IMATH_NOEXCEPT { @@ -2060,6 +1921,7 @@ Vec3::lengthTiny () const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline T Vec3::length () const IMATH_NOEXCEPT { @@ -2079,6 +1941,7 @@ Vec3::length2 () const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline const Vec3& Vec3::normalize () IMATH_NOEXCEPT { @@ -2101,6 +1964,7 @@ Vec3::normalize () IMATH_NOEXCEPT } template +template inline const Vec3& Vec3::normalizeExc () { @@ -2116,6 +1980,7 @@ Vec3::normalizeExc () } template +template IMATH_HOSTDEVICE inline const Vec3& Vec3::normalizeNonNull () IMATH_NOEXCEPT { @@ -2127,6 +1992,7 @@ Vec3::normalizeNonNull () IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline Vec3 Vec3::normalized () const IMATH_NOEXCEPT { @@ -2138,6 +2004,7 @@ Vec3::normalized () const IMATH_NOEXCEPT } template +template inline Vec3 Vec3::normalizedExc () const { @@ -2150,6 +2017,7 @@ Vec3::normalizedExc () const } template +template IMATH_HOSTDEVICE inline Vec3 Vec3::normalizedNonNull () const IMATH_NOEXCEPT { @@ -2480,6 +2348,7 @@ Vec4::operator/ (T a) const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T Vec4::lengthTiny () const IMATH_NOEXCEPT { @@ -2514,6 +2383,7 @@ Vec4::lengthTiny () const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline T Vec4::length () const IMATH_NOEXCEPT { @@ -2533,6 +2403,7 @@ Vec4::length2 () const IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE const inline Vec4& Vec4::normalize () IMATH_NOEXCEPT { @@ -2556,6 +2427,7 @@ Vec4::normalize () IMATH_NOEXCEPT } template +template const inline Vec4& Vec4::normalizeExc () { @@ -2572,6 +2444,7 @@ Vec4::normalizeExc () } template +template IMATH_HOSTDEVICE inline const Vec4& Vec4::normalizeNonNull () IMATH_NOEXCEPT { @@ -2584,6 +2457,7 @@ Vec4::normalizeNonNull () IMATH_NOEXCEPT } template +template IMATH_HOSTDEVICE inline Vec4 Vec4::normalized () const IMATH_NOEXCEPT { @@ -2595,6 +2469,7 @@ Vec4::normalized () const IMATH_NOEXCEPT } template +template inline Vec4 Vec4::normalizedExc () const { @@ -2607,6 +2482,7 @@ Vec4::normalizedExc () const } template +template IMATH_HOSTDEVICE inline Vec4 Vec4::normalizedNonNull () const IMATH_NOEXCEPT { -- 2.49.0.windows.1