From 6a33b97a84f9c0a60ede78b5db98647e9a48d6c9 Mon Sep 17 00:00:00 2001 From: Neil MacIntosh Date: Sat, 3 Mar 2018 19:12:45 -0800 Subject: Fix return type of templated span.subspan() (#625) * Added support for returning fixed-spize spans from subspan(). * Addressed issues from code review. * Took simpler approach to static data member. * Subtle fix to support MSVC 15. * Helps to not introduce extraneous > --- include/gsl/span | 28 ++++++++++++++++++++++++++-- tests/span_tests.cpp | 12 ++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/include/gsl/span b/include/gsl/span index e8ccb35..22e8459 100644 --- a/include/gsl/span +++ b/include/gsl/span @@ -45,8 +45,17 @@ #if _MSC_VER < 1910 #pragma push_macro("constexpr") #define constexpr /*constexpr*/ +#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND #endif // _MSC_VER < 1910 +#else // _MSC_VER + +// See if we have enough C++17 power to use a static constexpr data member +// without needing an out-of-line definition +#if !(defined(__cplusplus) && (__cplusplus >= 201703L)) +#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND +#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L)) + #endif // _MSC_VER #define GSL_NOEXCEPT noexcept @@ -302,6 +311,12 @@ namespace details private: index_type size_; }; + + template + struct calculate_subspan_type + { + using type = span; + }; } // namespace details // [span], class template span @@ -323,7 +338,11 @@ public: using size_type = index_type; - constexpr static const index_type extent = Extent; +#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) + static constexpr const index_type extent { Extent }; +#else + static constexpr index_type extent { Extent }; +#endif // [span.cons], span constructors, copy, assignment, and destructor template - constexpr span subspan() const + constexpr auto subspan() const -> typename details::calculate_subspan_type::type { Expects((Offset >= 0 && size() - Offset >= 0) && (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size()))); @@ -525,6 +544,11 @@ private: } }; +#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) +template +constexpr const typename span::index_type span::extent; +#endif + // [span.comparison], span comparison operators template diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index a71a228..20279ec 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -776,6 +776,7 @@ TEST_CASE("subspan") { span av = arr; CHECK((av.subspan<2, 2>().size() == 2)); + CHECK(decltype(av.subspan<2, 2>())::extent == 2); CHECK(av.subspan(2, 2).size() == 2); CHECK(av.subspan(2, 3).size() == 3); } @@ -783,13 +784,16 @@ TEST_CASE("subspan") { span av = arr; CHECK((av.subspan<0, 0>().size() == 0)); + CHECK(decltype(av.subspan<0,0>())::extent == 0); CHECK(av.subspan(0, 0).size() == 0); } { span av = arr; CHECK((av.subspan<0, 5>().size() == 5)); + CHECK(decltype(av.subspan<0, 5>())::extent == 5); CHECK(av.subspan(0, 5).size() == 5); + CHECK_THROWS_AS(av.subspan(0, 6).size(), fail_fast); CHECK_THROWS_AS(av.subspan(1, 5).size(), fail_fast); } @@ -797,14 +801,22 @@ TEST_CASE("subspan") { span av = arr; CHECK((av.subspan<4, 0>().size() == 0)); + CHECK(decltype(av.subspan<4, 0>())::extent == 0); CHECK(av.subspan(4, 0).size() == 0); CHECK(av.subspan(5, 0).size() == 0); CHECK_THROWS_AS(av.subspan(6, 0).size(), fail_fast); } + { + span av = arr; + CHECK((av.subspan<1>().size() == 4)); + CHECK(decltype(av.subspan<1>())::extent == 4); + } + { span av; CHECK((av.subspan<0, 0>().size() == 0)); + CHECK((decltype(av.subspan<0, 0>())::extent == 0)); CHECK(av.subspan(0, 0).size() == 0); CHECK_THROWS_AS((av.subspan<1, 0>().size()), fail_fast); } -- cgit v1.2.3