From b2f833876aaefb91ac5da878cf00b5c64fcf267b 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(); --- Modules/Core/Common/include/itkImageRegion.h | 60 +++++++++++++++++++ .../Core/Common/test/itkImageRegionGTest.cxx | 25 ++++++++ 2 files changed, 85 insertions(+) diff --git a/Modules/Core/Common/include/itkImageRegion.h b/Modules/Core/Common/include/itkImageRegion.h index 2efad05a2203..a64e10f604af 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,31 @@ std::ostream & operator<<(std::ostream & os, const ImageRegion & region); } // end namespace itk + +namespace std +{ + +/** `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> : std::integral_constant +{}; + +/** `std::tuple_element` specialization, needed for ImageRegion to support C++ structured binding. */ +template +struct tuple_element> + : conditional, itk::Size> +{ + static_assert(VTupleIndex < std::tuple_size_v>); +}; + +} // 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 7892aa1ad9a4..bdefd45d0f0a 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())); +}