Better_Software_Header_MobileBetter_Software_Header_Web

Find what you need - explore our website and developer resources

Structured Bindings with Qt SQL

for (auto [key, value] : map.asKeyValueRange()) {
        // ...
    }
auto [x, y] = mousePosition();
std::tuple<bool, QString, QString> employee;
    auto &[active, name, team_name] = employee;

    Employee employees[2];
    auto &[first_employee, second_employee] = employees;

    struct Employee {
        bool m_active;
        QString m_name;
        QString m_team;
    };
    Employee employee = ...;
    auto &[active, name, team_name] = employee;
auto &[name, team_name] = employee;
#include <utility>

    ...

    namespace std {
        template<>
        struct tuple_size<::Employee> {
            static constexpr std::size_t value = 2;
        };
    }
namespace std {
        template<>
        struct tuple_element<0, ::Employee> {
            // The type of m_name
            using type = QString;
        };

        template<>
        struct tuple_element<1, ::Employee> {
            // The type of m_team
            using type = QString;
        };
    }
template <std::size_t Idx>
     auto& get(Employee& employee) {
         if constexpr (Idx == 0) return employee.m_name;
         if constexpr (Idx == 1) return employee.m_team;
     }
class QSqlResultIterator {
        // ...
        QVariant operator[] (int index) const
        {
            return m_query.value(index);
        }
    };
class QSqlResultIterator {
        // ...
        template <std::size_t Idx>
        QVariant get() const
        {
            return m_query.value(index);
        }
    };
namespace std {
        template<std::size_t Idx>
        struct tuple_element<Idx, QSqlResultIterator> {
            using type = QVariant;
        };
    }
template <std::size_t FieldCount>
    class QSqlResultIterator {
        // ...
    };
template <std::size_t FieldCount>
    class QSqlResultIterator {
        template <std::size_t Idx>
        QVariant get() const
        {
            return m_query.value(index);
        }

        // ...
    };

    namespace std {
        template<std::size_t FieldCount>
        struct tuple_size<QSqlResultIterator<FieldCount>> {
            statuc constexpr std::size_t value = FieldCount;
        };

        template<std::size_t Idx, std::size_t FieldCount>
        struct tuple_element<Idx, QSqlResultIterator<FieldCount>> {
            using type = QVariant;
        };
    }
for (auto result: query) {
        // ...
    }
template <std::size_t FieldCount>
    class QSqlResultRange {
    public:
        QSqlResultRange(QSqlQuery query)
            : m_query(std::move(query))
        {}

        QSqlResultIterator<FieldCount> begin()
        {
            return { m_query };
        }

        QSqlResultSentinel end() const
        {
            return {};
        }

    private:
        QSqlQuery m_query;
    };
for (auto [active, name, team] : QSqlResultRange<3>(query)) {
        // ...
    }
// We want to allow the user to specify the types
    // of the fields in an SQL row
    template <typename ...Types>
    class QSqlResultTypedIterator {
    public:
        // The constructor and all the basic functions
        // we had in QSqlResultIterator remain unchanged

        QSqlResultTypedIterator(QSqlQuery& query)
            : m_query(query)
        {
            m_query.next();
        }

        QSqlResultTypedIterator& operator++()
        {
            m_query.next();
            return *this;
        }

        bool operator!=(QSqlResultSentinel sentinel) const
        {
            Q_UNUSED(sentinel);
            return m_query.isValid();
        }

        QSqlResultTypedIterator& operator*()
        {
            return *this;
        }

        // The only one that differs is the tuple-compatible
        // get member function. It can return different types
        // depending on the provided index.
        template <size_t Idx>
        auto get() const
        {
            using ResultType = std::tuple_element_t<Idx, std::tuple<Types...>>;
            // We can assert that the type stored inside of QVariant
            // is the type that we expect to be in it.
            Q_ASSERT(m_query.value(Idx).canView<ResultType>());

            // .value returns a QVariant. Then we call .value
            // on said variant to convert it to the desired type.
            return m_query.value(Idx).value<ResultType>();
        }

    private:
        QSqlQuery& m_query;
    };

    namespace std {
        // The tuple_size for QSqlResultTypedIterator is the
        // number of types inside of Types... which we can
        // easily get with sizeof...(Types)
        template<typename... Types>
        struct tuple_size<QSqlResultTypedIterator<Types...>> : public integral_constant<size_t, sizeof...(Types)> {};

        // The simplest way to implement tuple_element on our type
        // is to just base it on the implementation of std::tuple itself.
        // When we are asked for tuple_element<Idx, QSqlResultTypedIterator<Types...>>,
        // we will just replace QSqlResultTypedIterator with std::tuple,
        // and return tuple_element<Idx, std::tuple<Types...>>
        template<std::size_t Idx, typename... Types>
        struct tuple_element<Idx, QSqlResultTypedIterator <Types...>>:
               tuple_element<Idx, std::tuple              <Types...>>
        {
        };
    }

    // The complex part was in the QSqlResultTypedIterator, and the
    // range object remains as simple as QSqlResultIterator was.
    // The only change is that FieldCount is replaced by Types... everywhere
    template <typename ...Types>
    class QSqlResultTypedRange {
    public:
        QSqlResultTypedRange(QSqlQuery query)
            : m_query(std::move(query))
        {
        }

        QSqlResultTypedIterator<Types...> begin()
        {
            return { m_query };
        }

        QSqlResultSentinel end() const
        {
            return {};
        }

    private:
        QSqlQuery m_query;
    };
for (auto [active, name, team] : QSqlResultTypedRange<bool, QString, QString>(query)) {
        qDebug() << "active(bool):" << active;
        qDebug() << "name(QString):" << name;
        qDebug() << "team(QString):" << team;
    }

About KDAB


IvanČukić

Ivan Čukić

Senior Software Engineer

Learn Modern C++

Learn more