Skip to content

Commit 6a33b97

Browse files
Fix return type of templated span.subspan() (microsoft#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 >
1 parent cbd64c9 commit 6a33b97

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

include/gsl/span

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,17 @@
4545
#if _MSC_VER < 1910
4646
#pragma push_macro("constexpr")
4747
#define constexpr /*constexpr*/
48+
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
4849

4950
#endif // _MSC_VER < 1910
51+
#else // _MSC_VER
52+
53+
// See if we have enough C++17 power to use a static constexpr data member
54+
// without needing an out-of-line definition
55+
#if !(defined(__cplusplus) && (__cplusplus >= 201703L))
56+
#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
57+
#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
58+
5059
#endif // _MSC_VER
5160

5261
#define GSL_NOEXCEPT noexcept
@@ -302,6 +311,12 @@ namespace details
302311
private:
303312
index_type size_;
304313
};
314+
315+
template <class ElementType, std::ptrdiff_t Extent, std::ptrdiff_t Offset, std::ptrdiff_t Count>
316+
struct calculate_subspan_type
317+
{
318+
using type = span<ElementType, Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : Extent)>;
319+
};
305320
} // namespace details
306321

307322
// [span], class template span
@@ -323,7 +338,11 @@ public:
323338

324339
using size_type = index_type;
325340

326-
constexpr static const index_type extent = Extent;
341+
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
342+
static constexpr const index_type extent { Extent };
343+
#else
344+
static constexpr index_type extent { Extent };
345+
#endif
327346

328347
// [span.cons], span constructors, copy, assignment, and destructor
329348
template <bool Dependent = false,
@@ -412,7 +431,7 @@ public:
412431
}
413432

414433
template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
415-
constexpr span<element_type, Count> subspan() const
434+
constexpr auto subspan() const -> typename details::calculate_subspan_type<ElementType, Extent, Offset, Count>::type
416435
{
417436
Expects((Offset >= 0 && size() - Offset >= 0) &&
418437
(Count == dynamic_extent || (Count >= 0 && Offset + Count <= size())));
@@ -525,6 +544,11 @@ private:
525544
}
526545
};
527546

547+
#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
548+
template <class ElementType, std::ptrdiff_t Extent>
549+
constexpr const typename span<ElementType, Extent>::index_type span<ElementType, Extent>::extent;
550+
#endif
551+
528552

529553
// [span.comparison], span comparison operators
530554
template <class ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>

tests/span_tests.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,35 +776,47 @@ TEST_CASE("subspan")
776776
{
777777
span<int, 5> av = arr;
778778
CHECK((av.subspan<2, 2>().size() == 2));
779+
CHECK(decltype(av.subspan<2, 2>())::extent == 2);
779780
CHECK(av.subspan(2, 2).size() == 2);
780781
CHECK(av.subspan(2, 3).size() == 3);
781782
}
782783

783784
{
784785
span<int, 5> av = arr;
785786
CHECK((av.subspan<0, 0>().size() == 0));
787+
CHECK(decltype(av.subspan<0,0>())::extent == 0);
786788
CHECK(av.subspan(0, 0).size() == 0);
787789
}
788790

789791
{
790792
span<int, 5> av = arr;
791793
CHECK((av.subspan<0, 5>().size() == 5));
794+
CHECK(decltype(av.subspan<0, 5>())::extent == 5);
792795
CHECK(av.subspan(0, 5).size() == 5);
796+
793797
CHECK_THROWS_AS(av.subspan(0, 6).size(), fail_fast);
794798
CHECK_THROWS_AS(av.subspan(1, 5).size(), fail_fast);
795799
}
796800

797801
{
798802
span<int, 5> av = arr;
799803
CHECK((av.subspan<4, 0>().size() == 0));
804+
CHECK(decltype(av.subspan<4, 0>())::extent == 0);
800805
CHECK(av.subspan(4, 0).size() == 0);
801806
CHECK(av.subspan(5, 0).size() == 0);
802807
CHECK_THROWS_AS(av.subspan(6, 0).size(), fail_fast);
803808
}
804809

810+
{
811+
span<int, 5> av = arr;
812+
CHECK((av.subspan<1>().size() == 4));
813+
CHECK(decltype(av.subspan<1>())::extent == 4);
814+
}
815+
805816
{
806817
span<int> av;
807818
CHECK((av.subspan<0, 0>().size() == 0));
819+
CHECK((decltype(av.subspan<0, 0>())::extent == 0));
808820
CHECK(av.subspan(0, 0).size() == 0);
809821
CHECK_THROWS_AS((av.subspan<1, 0>().size()), fail_fast);
810822
}

0 commit comments

Comments
 (0)