QSpan: make adl_begin() etc SFINAE-friendly

The definition of iterator_t, and, therefore, of is_compatible_range
depends on this, otherwise say, 0, is being treated as a valid range
and hits a hard error in adl_begin() when trying to call begin(int&).

TIL: decltype(auto) does _not_ SFINAE.

Fix by calculating the return type manually, re-enabing SFINAE.

Pick-to: 6.6
Change-Id: Icacd70554f4050ecaeb396c9ae60bc4f21a220c9
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit 94e122c594a3697b98dcc99a9e332b0f5e816d2d)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2024-01-24 11:36:35 +01:00 committed by Qt Cherry-pick Bot
parent 346b5931a7
commit 1b559b25a6
2 changed files with 17 additions and 3 deletions

View File

@ -76,14 +76,25 @@ using is_qualification_conversion =
template <typename From, typename To>
constexpr inline bool is_qualification_conversion_v = is_qualification_conversion<From, To>::value;
namespace AdlTester {
#define MAKE_ADL_TEST(what) \
using std:: what; /* bring into scope */ \
template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
/* end */
MAKE_ADL_TEST(begin)
MAKE_ADL_TEST(data)
MAKE_ADL_TEST(size)
#undef MAKE_ADL_TEST
}
// Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s,
// not doing the extra work C++20 requires
template <typename Range>
decltype(auto) adl_begin(Range &&r) { using std::begin; return begin(r); }
AdlTester::begin_result<Range> adl_begin(Range &&r) { using std::begin; return begin(r); }
template <typename Range>
decltype(auto) adl_data(Range &&r) { using std::data; return data(r); }
AdlTester::data_result<Range> adl_data(Range &&r) { using std::data; return data(r); }
template <typename Range>
decltype(auto) adl_size(Range &&r) { using std::size; return size(r); }
AdlTester::size_result<Range> adl_size(Range &&r) { using std::size; return size(r); }
// Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin)
// This one uses adl_begin() instead.

View File

@ -96,6 +96,9 @@ static_assert(!std::is_convertible_v<QSpan<const int, 42>, std::span<int, 42>>);
static_assert(!std::is_convertible_v<QSpan<const int, 0>, std::span<int, 0>>);
#endif // __cpp_lib_span
// Spans don't convert from nonsense:
static_assert(!std::is_constructible_v<QSpan<const int>, int&&>);
class tst_QSpan : public QObject
{
Q_OBJECT