From 72aa9a602bd92b665acc915d8df4bd00a27c98f0 Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Tue, 12 Dec 2023 12:58:07 +0100 Subject: [PATCH] ENH: `ImageRegion` support C++17 structured binding Added `get()` member functions and specializations of `std::tuple_size` and `std::tuple_element` for ImageRegion, in order to support structured binding, for example: auto [index, size] = image.GetRequestedRegion(); Suppressed the undeserved Clang-Tidy "cert-dcl58-cpp" warnings that appeared when specializing those `std` templates. --- .github/workflows/itk_dict.txt | 5 ++ Modules/Core/Common/include/itkImageRegion.h | 64 +++++++++++++++++++ .../Core/Common/test/itkImageRegionGTest.cxx | 25 ++++++++ 3 files changed, 94 insertions(+) diff --git a/.github/workflows/itk_dict.txt b/.github/workflows/itk_dict.txt index 3926df557f6..e5628ab6f69 100644 --- a/.github/workflows/itk_dict.txt +++ b/.github/workflows/itk_dict.txt @@ -136,6 +136,8 @@ Minc MincTransformIO Minkowski Musser +NOLINTBEGIN +NOLINTEND NVidia Negahdaripour Newmark @@ -279,6 +281,7 @@ callosum centerline cdf cdfs +cert cfl cgi cha @@ -303,6 +306,7 @@ confocal cooccurrence costless cp +cpp cr cranio creativecommons @@ -322,6 +326,7 @@ d'Attente dDwWmMyY da dat +dcl dcmimage dcmtk datablock diff --git a/Modules/Core/Common/include/itkImageRegion.h b/Modules/Core/Common/include/itkImageRegion.h index 2efad05a220..c1596242f65 100644 --- a/Modules/Core/Common/include/itkImageRegion.h +++ b/Modules/Core/Common/include/itkImageRegion.h @@ -33,6 +33,8 @@ #include "itkSize.h" #include "itkContinuousIndex.h" #include "itkMath.h" +#include // For conditional and integral_constant. +#include // For tuple_element and tuple_size. // Macro added to each `ImageRegion` member function that overrides a virtual member function of `Region`. In the // future, `ImageRegion` will no longer inherit from `Region`, so then those `ImageRegion` member functions will no @@ -357,6 +359,39 @@ class ITK_TEMPLATE_EXPORT ImageRegion final SliceRegion Slice(const unsigned int dim) const; + /** Supports tuple-like access: `get<0>()` returns a reference to the index and `get<1>()` returns a reference to the + * size of the region. */ + template + [[nodiscard]] auto & + get() + { + if constexpr (VTupleIndex == 0) + { + return m_Index; + } + else + { + static_assert(VTupleIndex == 1); + return m_Size; + } + } + + /** Supports tuple-like access. Const overload. */ + template + [[nodiscard]] const auto & + get() const + { + if constexpr (VTupleIndex == 0) + { + return m_Index; + } + else + { + static_assert(VTupleIndex == 1); + return m_Size; + } + } + protected: /** Methods invoked by Print() to print information about the object * including superclasses. Typically not called by the user (use Print() @@ -378,6 +413,35 @@ std::ostream & operator<<(std::ostream & os, const ImageRegion & region); } // end namespace itk + +namespace std +{ +// NOLINTBEGIN(cert-dcl58-cpp) +// Locally suppressed the following warning from Clang-Tidy (LLVM 17.0.1), as it appears undeserved. +// > warning: modification of 'std' namespace can result in undefined behavior [cert-dcl58-cpp] + +/** `std::tuple_size` specialization, needed for ImageRegion to support C++ structured binding. + * + * Example, using structured binding to retrieve the index and size of a region: + \code + auto [index, size] = image.GetRequestedRegion(); + \endcode + */ +template +struct tuple_size> : integral_constant +{}; + +/** `std::tuple_element` specialization, needed for ImageRegion to support C++ structured binding. */ +template +struct tuple_element> + : conditional, itk::Size> +{ + static_assert(VTupleIndex < tuple_size_v>); +}; + +// NOLINTEND(cert-dcl58-cpp) +} // namespace std + #undef itkRegionOverrideMacro #ifndef ITK_MANUAL_INSTANTIATION diff --git a/Modules/Core/Common/test/itkImageRegionGTest.cxx b/Modules/Core/Common/test/itkImageRegionGTest.cxx index 7892aa1ad9a..bdefd45d0f0 100644 --- a/Modules/Core/Common/test/itkImageRegionGTest.cxx +++ b/Modules/Core/Common/test/itkImageRegionGTest.cxx @@ -194,3 +194,28 @@ TEST(ImageRegion, CropLargerToSmallerRegionAndViceVersa) } } } + + +// Tests C++ structured binding of an ImageRegion. +TEST(ImageRegion, SupportsStructuredBinding) +{ + using RegionType = itk::ImageRegion<2>; + using IndexType = RegionType::IndexType; + using SizeType = RegionType::SizeType; + + RegionType region{}; + auto && [index, size] = region; + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + EXPECT_EQ(&index, &(region.GetIndex())); + EXPECT_EQ(&size, &(region.GetSize())); + + const RegionType constRegion{}; + auto && [constIndex, constSize] = constRegion; + + static_assert(std::is_same_v); + static_assert(std::is_same_v); + EXPECT_EQ(&constIndex, &(constRegion.GetIndex())); + EXPECT_EQ(&constSize, &(constRegion.GetSize())); +}