From 1659a0a12bdfbf2bdfe905f697ea06a4332f4b20 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@qt.io>
Date: Thu, 27 Jun 2019 10:23:21 +0200
Subject: [PATCH] WIP: Add QRelaxedOverload

Make it possible to write qRelaxedOverload<QString> for a signal that
emits "const QString &", which enables uic to write out Qt 5
connection syntax.

todo: wait until MSVC handles it:

./../src/corelib/global/qrelaxedoverload.h(188): fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'msc1.cpp', line 1518)
 To work around this problem, try simplifying or changing the program near the locations listed above.

Initial-patch-by: Fabian.Kosmale@qt.io
Task-number: QTBUG-76375
Change-Id: Ia00ebe4cff341e4ac096aeb0d6a7a9f33eddb294
---
 src/corelib/global/global.pri                 |   1 +
 src/corelib/global/qrelaxedoverload.h         | 201 ++++++++++++++++++
 tests/auto/corelib/global/global.pro          |   3 +-
 .../qrelaxedoverload/qrelaxedoverload.pro     |   5 +
 .../qrelaxedoverload/tst_qrelaxedoverload.cpp |  77 +++++++
 5 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 src/corelib/global/qrelaxedoverload.h
 create mode 100644 tests/auto/corelib/global/qrelaxedoverload/qrelaxedoverload.pro
 create mode 100644 tests/auto/corelib/global/qrelaxedoverload/tst_qrelaxedoverload.cpp

diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index 1da69aba9b..2a06ad27bb 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -24,6 +24,7 @@ HEADERS +=  \
         global/qflags.h \
         global/qrandom.h \
         global/qrandom_p.h \
+        global/qrelaxedoverload.h \
         global/qhooks_p.h \
         global/qversiontagging.h
 
diff --git a/src/corelib/global/qrelaxedoverload.h b/src/corelib/global/qrelaxedoverload.h
new file mode 100644
index 0000000000..e898d6ba7b
--- /dev/null
+++ b/src/corelib/global/qrelaxedoverload.h
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#ifndef QRELAXEDOVERLOAD_H
+#define QRELAXEDOVERLOAD_H
+
+QT_BEGIN_NAMESPACE
+
+#include <type_traits>
+
+namespace QtPrivate {
+
+// a type list for further operations
+
+template <bool NonEmpty, typename... List>
+struct typelist_helper;
+
+template<typename Head, typename... Tail>
+struct splitter
+{
+    using head = Head;
+    using tail = typelist_helper<sizeof...(Tail) != 0, Tail...>;
+};
+
+template <typename... List>
+struct typelist_helper<true, List...>
+{
+
+    static constexpr bool is_empty = false;
+    using head = typename splitter<List...>::head;
+    using tail = typename splitter<List...>::tail;
+
+    template <template <typename...> class T> using apply = T<List...>;
+    template <template <typename...> class F> using map = typelist_helper<true, typename F<List>::result...>;
+
+    template <typename ...T> using append = typelist_helper<true, List...,T...>;
+    template <typename T> using prepend = typelist_helper<true, T, List...>;
+};
+
+template <typename... List>
+struct typelist_helper<false, List...>
+{
+
+    static constexpr bool is_empty = true;
+    using tail = typelist_helper<false>;
+
+    template <template <typename...> class T> using apply = T<>;
+    template <template <typename...> class F> using map = tail;
+
+    template <typename ...T> using append = typelist_helper<true, T...>;
+    template <typename T> using prepend = typelist_helper<true, T>;
+};
+
+template<typename... Ts>
+using typelist = typelist_helper<sizeof...(Ts) != 0, Ts...>;
+
+// all_combinations(_generator): for a list of types, generate all permutations of value and const ref
+// all_combinations_generator<int, float> == [ [const int&, const float&], [const int&, float], [int, const float&], [int, float] ]
+
+template<typename T,typename Enable=void>
+struct all_combinations;
+
+template<typename... Ts>
+struct all_combinations_generator;
+
+template<typename T>
+struct all_combinations<T, typename std::enable_if<!T::is_empty>::type>
+{
+    // T -> [T] -> [T]
+    template <typename New, typename List>
+        struct prepend {
+        using result = typename List::template prepend<New>;
+    };
+
+    template<typename Element, typename ListOfLists>
+    struct prepend_all
+    {
+        template<typename List>
+        using prependE = prepend<Element, List>; // [T] -> [T]
+        using result = typename ListOfLists::template map<prependE>;
+    };
+
+
+    using result_rec = typename T::tail:: template apply<all_combinations_generator>::result; // [[T]]
+
+    // [[T] -> [[T]]
+    template<typename ListOfLists>
+    using const_lvalue_ref_prepender = typename prepend_all<const typename T::head&, ListOfLists>::result;
+
+
+    template<typename ListOfLists>
+    using lvalue_prepender = typename prepend_all<typename T::head, ListOfLists>::result;
+
+
+    using result_cr = const_lvalue_ref_prepender<result_rec>;
+    using result_v = lvalue_prepender<result_rec>; // [[T]]
+
+    using result = typename result_v::template apply<result_cr::template append>;
+};
+
+template<typename T>
+struct all_combinations<T, typename std::enable_if<T::is_empty>::type>
+{
+    using result = typelist<typelist<>>;
+};
+
+template<typename... Ts>
+struct all_combinations_generator
+{
+    using result = typename all_combinations<typelist<Ts...>>::result;
+};
+
+static_assert(std::is_same<
+    typename all_combinations_generator<>::result,
+    typelist<typelist<>>
+    >::value, "");
+
+
+static_assert(std::is_same<
+    typename all_combinations_generator<int>::result,
+    typelist<typelist<const int&>, typelist<int>>
+    >::value, "");
+
+static_assert(std::is_same<
+    typename all_combinations_generator<int, float>::result,
+    typelist<typelist<const int&, const float&>, typelist<const int&, float>, typelist<int, const float&>, typelist<int, float>>
+    >::value, "");
+
+// use all_combinations_generator to create the desired QOverload
+
+template<typename... Args>
+struct operator_provider
+{
+    template <typename R, typename T>
+    constexpr auto operator()(R (T::*ptr)(Args...)) const noexcept -> decltype(ptr)
+    { return ptr; }
+};
+
+template<typename... Args>
+struct operator_provider_const
+{
+    template <typename R, typename T>
+    constexpr auto operator()(R (T::*ptr)(Args...) const) const noexcept -> decltype(ptr)
+    { return ptr; }
+};
+
+template <typename... Args>
+struct QRelaxedOverloadHelper : Args::template apply<operator_provider>..., Args::template apply<operator_provider_const>...
+{
+    using Args::template apply<operator_provider>::operator()...;
+    using Args::template apply<operator_provider_const>::operator()...;
+};
+
+} // namespace QtPrivate
+
+template <typename... Args>
+struct QRelaxedOverload : QtPrivate::all_combinations_generator<Args...>::result::template apply<QtPrivate::QRelaxedOverloadHelper> {};
+
+template <typename... Args> constexpr  QRelaxedOverload<Args...> qRelaxedOverload = {};
+
+QT_END_NAMESPACE
+
+#endif // QRELAXEDOVERLOAD_H
diff --git a/tests/auto/corelib/global/global.pro b/tests/auto/corelib/global/global.pro
index 139e073644..f8754389cd 100644
--- a/tests/auto/corelib/global/global.pro
+++ b/tests/auto/corelib/global/global.pro
@@ -11,4 +11,5 @@ SUBDIRS=\
     qlogging \
     qtendian \
     qglobalstatic \
-    qhooks
+    qhooks \
+    qrelaxedoverload
diff --git a/tests/auto/corelib/global/qrelaxedoverload/qrelaxedoverload.pro b/tests/auto/corelib/global/qrelaxedoverload/qrelaxedoverload.pro
new file mode 100644
index 0000000000..5dbcf6e70f
--- /dev/null
+++ b/tests/auto/corelib/global/qrelaxedoverload/qrelaxedoverload.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qrelaxedoverload
+QT = core testlib
+SOURCES = tst_qrelaxedoverload.cpp
+contains(QT_CONFIG, c++1z): CONFIG += c++1z
diff --git a/tests/auto/corelib/global/qrelaxedoverload/tst_qrelaxedoverload.cpp b/tests/auto/corelib/global/qrelaxedoverload/tst_qrelaxedoverload.cpp
new file mode 100644
index 0000000000..959fcabea8
--- /dev/null
+++ b/tests/auto/corelib/global/qrelaxedoverload/tst_qrelaxedoverload.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <qrelaxedoverload.h>
+#include <QString>
+
+class tst_QRelaxedOverload: public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void testqOverload();
+};
+
+struct Overloaded
+{
+    void fvv(QByteArray, QString) {}
+    void fvc(QByteArray, const QString &) {}
+    void fcv(const QByteArray &, QString) {}
+    void fcc(const QByteArray &, const QString &) {}
+
+    void const_Fvv(QByteArray, QString) {}
+    void const_Fvc(QByteArray, const QString &) {}
+    void const_Fcv(const QByteArray &, QString) {}
+    void const_Fcc(const QByteArray &, const QString &) {}
+};
+
+void tst_QRelaxedOverload::testqOverload()
+{
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::fvv))
+            == &Overloaded::fvv);
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::fvc))
+            == &Overloaded::fvc);
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::fcv))
+            == &Overloaded::fcv);
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::fcc))
+            == &Overloaded::fcc);
+
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::const_Fvv))
+            == &Overloaded::const_Fvv);
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::const_Fvc))
+            == &Overloaded::const_Fvc);
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::const_Fcv))
+            == &Overloaded::const_Fcv);
+    QVERIFY((qRelaxedOverload<QByteArray, QString>(&Overloaded::const_Fcc))
+            == &Overloaded::const_Fcc);
+}
+
+QTEST_APPLESS_MAIN(tst_QRelaxedOverload)
+#include "tst_qrelaxedoverload.moc"
-- 
2.17.1

