// Copyright (c) 2023 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include namespace spannable { struct Ignore { template Ignore(T&&) {} }; template bool Spannable(T&& value, decltype(Span{value})* enable = nullptr) { return true; } bool Spannable(Ignore) { return false; } struct SpannableYes { int* data(); int* begin(); int* end(); size_t size(); }; struct SpannableNo { void data(); size_t size(); }; } // namespace spannable using namespace spannable; BOOST_AUTO_TEST_SUITE(span_tests) // Make sure template Span template deduction guides accurately enable calls to // Span constructor overloads that work, and disable calls to constructor overloads that // don't work. This makes it is possible to use the Span constructor in a SFINAE // contexts like in the Spannable function above to detect whether types are or // aren't compatible with Spans at compile time. // // Previously there was a bug where writing a SFINAE check for vector was // not possible, because in libstdc++ vector has a data() member // returning void, and the Span template guide ignored the data() return value, // so the template substitution would succeed, but the constructor would fail, // resulting in a fatal compile error, rather than a SFINAE error that could be // handled. BOOST_AUTO_TEST_CASE(span_constructor_sfinae) { BOOST_CHECK(Spannable(std::vector{})); BOOST_CHECK(!Spannable(std::set{})); BOOST_CHECK(!Spannable(std::vector{})); BOOST_CHECK(Spannable(std::array{})); BOOST_CHECK(Spannable(Span{})); BOOST_CHECK(Spannable("char array")); BOOST_CHECK(Spannable(SpannableYes{})); BOOST_CHECK(!Spannable(SpannableNo{})); } BOOST_AUTO_TEST_SUITE_END()