Short live QT_ENABLE_P0846_SEMANTICS_FOR!

In C++17, unqualified lookup doesn't find function templates that
require ADL from a call with explicit template arguments, unless
another function template of that name is in scope (otherwise, the <
is parsed as operator less-than instead).

P0846, merged for C++20, fixes this to repeat the name lookup, parsing
the < as indicating a template.

We have API in Qt (Tuple Protocol for some types, e.g. QPoint) that
work for the purpose of Structured Bindings, but don't work for manual
unqualified calls when P0846 semantics are missing, and we're adding
more, to QVariant, so add a macro to handle the issue.

The macro simply declares a function template overload of the given
name for a throw-away struct, thereby bringing, for that one name,
P0846 semantics into C++17.

When we require C++20, we can drop this again.

Amends:
- fb6b7869e8 for QPoint(F)
- 8ae9431c79 for QMargins(F)
- 0e22001a3b for the rest

[ChangeLog][QtCore][QSize/F, QMargins/F, QPoint/F] Fixed manual
get<I>() calls (Tuple Protocol) in C++17 mode.

Task-number: QTBUG-111598
Change-Id: I2ffaef12c5bb6d82f75ce78a7c03c6789dfa0691
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Marc Mutz 2023-03-14 16:23:31 +01:00
parent eafe577041
commit eb9c8042cf
9 changed files with 137 additions and 0 deletions

View File

@ -1358,6 +1358,20 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
# endif
#endif
#if __cplusplus >= 202002L // P0846 doesn't have a feature macro :/
# define QT_COMPILER_HAS_P0846
#endif
#ifdef QT_COMPILER_HAS_P0846
# define QT_ENABLE_P0846_SEMANTICS_FOR(func)
#else
class QT_CLASS_JUST_FOR_P0846_SIMULATION;
# define QT_ENABLE_P0846_SEMANTICS_FOR(func) \
template <typename T> \
void func (QT_CLASS_JUST_FOR_P0846_SIMULATION *); \
/* end */
#endif // !P0846
#endif // __cplusplus
#endif // QCOMPILERDETECTION_H

View File

@ -11,6 +11,8 @@
QT_BEGIN_NAMESPACE
QT_ENABLE_P0846_SEMANTICS_FOR(get)
class QMarginsF;
/*****************************************************************************

View File

@ -15,6 +15,8 @@ struct CGPoint;
QT_BEGIN_NAMESPACE
QT_ENABLE_P0846_SEMANTICS_FOR(get)
class QPointF;
class QPoint

View File

@ -17,6 +17,8 @@ struct CGSize;
QT_BEGIN_NAMESPACE
// QT_ENABLE_P0846_SEMANTICS_FOR(get) // from qmargins.h
class QSizeF;
class Q_CORE_EXPORT QSize

View File

@ -1,6 +1,35 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QMargins>
#ifdef QVARIANT_H
# error "This test requires qmargins.h to not include qvariant.h"
#endif
// don't assume <type_traits>
template <typename T, typename U>
constexpr inline bool my_is_same_v = false;
template <typename T>
constexpr inline bool my_is_same_v<T, T> = true;
#define CHECK(cvref) \
static_assert(my_is_same_v<decltype(get<0>(std::declval<QMargins cvref >())), int cvref >); \
static_assert(my_is_same_v<decltype(get<1>(std::declval<QMargins cvref >())), int cvref >); \
static_assert(my_is_same_v<decltype(get<2>(std::declval<QMargins cvref >())), int cvref >); \
static_assert(my_is_same_v<decltype(get<3>(std::declval<QMargins cvref >())), int cvref >); \
\
static_assert(my_is_same_v<decltype(get<0>(std::declval<QMarginsF cvref >())), qreal cvref >); \
static_assert(my_is_same_v<decltype(get<1>(std::declval<QMarginsF cvref >())), qreal cvref >); \
static_assert(my_is_same_v<decltype(get<2>(std::declval<QMarginsF cvref >())), qreal cvref >); \
static_assert(my_is_same_v<decltype(get<3>(std::declval<QMarginsF cvref >())), qreal cvref >)
CHECK(&);
CHECK(const &);
CHECK(&&);
CHECK(const &&);
#undef CHECK
#include <QTest>
#include <qmargins.h>

View File

@ -1,6 +1,28 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QPoint>
#ifdef QVARIANT_H
# error "This test requires qpoint.h to not include qvariant.h"
#endif
// don't assume <type_traits>
template <typename T, typename U>
constexpr inline bool my_is_same_v = false;
template <typename T>
constexpr inline bool my_is_same_v<T, T> = true;
#define CHECK(cvref) \
static_assert(my_is_same_v<decltype(get<0>(std::declval<QPoint cvref >())), int cvref >); \
static_assert(my_is_same_v<decltype(get<1>(std::declval<QPoint cvref >())), int cvref >)
CHECK(&);
CHECK(const &);
CHECK(&&);
CHECK(const &&);
#undef CHECK
#include <QTest>
#include <QBuffer>

View File

@ -1,6 +1,28 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QPointF>
#ifdef QVARIANT_H
# error "This test requires qpoint.h to not include qvariant.h"
#endif
// don't assume <type_traits>
template <typename T, typename U>
constexpr inline bool my_is_same_v = false;
template <typename T>
constexpr inline bool my_is_same_v<T, T> = true;
#define CHECK(cvref) \
static_assert(my_is_same_v<decltype(get<0>(std::declval<QPointF cvref >())), qreal cvref >); \
static_assert(my_is_same_v<decltype(get<1>(std::declval<QPointF cvref >())), qreal cvref >)
CHECK(&);
CHECK(const &);
CHECK(&&);
CHECK(const &&);
#undef CHECK
#include <QTest>
#include <QBuffer>

View File

@ -1,6 +1,28 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QSize>
#ifdef QVARIANT_H
# error "This test requires qsize.h to not include qvariant.h"
#endif
// don't assume <type_traits>
template <typename T, typename U>
constexpr inline bool my_is_same_v = false;
template <typename T>
constexpr inline bool my_is_same_v<T, T> = true;
#define CHECK(cvref) \
static_assert(my_is_same_v<decltype(get<0>(std::declval<QSize cvref >())), int cvref >); \
static_assert(my_is_same_v<decltype(get<1>(std::declval<QSize cvref >())), int cvref >)
CHECK(&);
CHECK(const &);
CHECK(&&);
CHECK(const &&);
#undef CHECK
#include <QTest>
#include <qsize.h>

View File

@ -1,6 +1,28 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QSizeF>
#ifdef QVARIANT_H
# error "This test requires qsize.h to not include qvariant.h"
#endif
// don't assume <type_traits>
template <typename T, typename U>
constexpr inline bool my_is_same_v = false;
template <typename T>
constexpr inline bool my_is_same_v<T, T> = true;
#define CHECK(cvref) \
static_assert(my_is_same_v<decltype(get<0>(std::declval<QSizeF cvref >())), qreal cvref >); \
static_assert(my_is_same_v<decltype(get<1>(std::declval<QSizeF cvref >())), qreal cvref >)
CHECK(&);
CHECK(const &);
CHECK(&&);
CHECK(const &&);
#undef CHECK
#include <QTest>
#include <qsize.h>