span_tests.cpp raw
1 // Copyright (c) 2023 The Limenka developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <span.h>
6
7 #include <boost/test/unit_test.hpp>
8 #include <array>
9 #include <set>
10 #include <vector>
11
12 namespace {
13 struct Ignore
14 {
15 template<typename T> Ignore(T&&) {}
16 };
17 template<typename T>
18 bool Spannable(T&& value, decltype(Span{value})* enable = nullptr)
19 {
20 return true;
21 }
22 bool Spannable(Ignore)
23 {
24 return false;
25 }
26
27 #if defined(__clang__)
28 # pragma clang diagnostic push
29 # pragma clang diagnostic ignored "-Wunneeded-member-function"
30 # pragma clang diagnostic ignored "-Wunused-member-function"
31 #endif
32 struct SpannableYes
33 {
34 int* data();
35 size_t size();
36 };
37 struct SpannableNo
38 {
39 void* data();
40 size_t size();
41 };
42 #if defined(__clang__)
43 # pragma clang diagnostic pop
44 #endif
45 } // namespace
46
47 BOOST_AUTO_TEST_SUITE(span_tests)
48
49 // Make sure template Span template deduction guides accurately enable calls to
50 // Span constructor overloads that work, and disable calls to constructor overloads that
51 // don't work. This makes it is possible to use the Span constructor in a SFINAE
52 // contexts like in the Spannable function above to detect whether types are or
53 // aren't compatible with Spans at compile time.
54 //
55 // Previously there was a bug where writing a SFINAE check for vector<bool> was
56 // not possible, because in libstdc++ vector<bool> has a data() member
57 // returning void*, and the Span template guide ignored the data() return value,
58 // so the template substitution would succeed, but the constructor would fail,
59 // resulting in a fatal compile error, rather than a SFINAE error that could be
60 // handled.
61 BOOST_AUTO_TEST_CASE(span_constructor_sfinae)
62 {
63 BOOST_CHECK(Spannable(std::vector<int>{}));
64 BOOST_CHECK(!Spannable(std::set<int>{}));
65 BOOST_CHECK(!Spannable(std::vector<bool>{}));
66 BOOST_CHECK(Spannable(std::array<int, 3>{}));
67 BOOST_CHECK(Spannable(Span<int>{}));
68 BOOST_CHECK(Spannable("char array"));
69 BOOST_CHECK(Spannable(SpannableYes{}));
70 BOOST_CHECK(!Spannable(SpannableNo{}));
71 }
72
73 BOOST_AUTO_TEST_SUITE_END()
74