diff --git a/src/blackmisc/tuple.h b/src/blackmisc/tuple.h index 07edd4229..ea82da2b7 100644 --- a/src/blackmisc/tuple.h +++ b/src/blackmisc/tuple.h @@ -51,13 +51,13 @@ friend class T; \ static_assert(Private::HasEnabledTupleConversion::value, \ "Missing BLACK_ENABLE_TUPLE_CONVERSION macro in " #T); \ - static auto toTuple(const T &o) -> decltype(std::tie MEMBERS) \ + static auto toTuple(const T &o) -> decltype(BlackMisc::tie MEMBERS) \ { \ - return std::tie MEMBERS; \ + return BlackMisc::tie MEMBERS; \ } \ - static auto toTuple(T &o) -> decltype(std::tie MEMBERS) \ + static auto toTuple(T &o) -> decltype(BlackMisc::tie MEMBERS) \ { \ - return std::tie MEMBERS; \ + return BlackMisc::tie MEMBERS; \ } \ static const QStringList &jsonMembers() \ { \ @@ -80,13 +80,13 @@ friend class T; \ static_assert(Private::HasEnabledTupleConversion>::value, \ "Missing BLACK_ENABLE_TUPLE_CONVERSION macro in " #T); \ - static auto toTuple(const T &o) -> decltype(std::tie MEMBERS) \ + static auto toTuple(const T &o) -> decltype(BlackMisc::tie MEMBERS) \ { \ - return std::tie MEMBERS; \ + return BlackMisc::tie MEMBERS; \ } \ - static auto toTuple(T &o) -> decltype(std::tie MEMBERS) \ + static auto toTuple(T &o) -> decltype(BlackMisc::tie MEMBERS) \ { \ - return std::tie MEMBERS; \ + return BlackMisc::tie MEMBERS; \ } \ static const QStringList &jsonMembers() \ { \ @@ -152,6 +152,19 @@ namespace BlackMisc #ifdef Q_COMPILER_VARIADIC_TEMPLATES + /*! + * \brief Works like std::tie but with special handling for any argument which are tuples. + * \details Returns a tuple of references to its arguments which can be used in the same way as + * std::tie, except for arguments which are themselves tuples. Arguments which are tuples + * are copied into the result tuple by value. This enables nesting of calls to tie within + * other calls to tie, to workaround implementations which have a maximum tuple size. + */ + template + auto tie(Ts &&... args) -> decltype(std::make_tuple(Private::tieHelper(args)...)) + { + return std::make_tuple(Private::tieHelper(args)...); + } + /*! * \brief Lexicographical tuple comparison function which is CValueObject-aware. * \details Tuple members which are CValueObjects are compared using the compare() friend function of CValueObject; @@ -159,7 +172,7 @@ namespace BlackMisc * \ingroup Tuples */ template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { return Private::TupleHelper::compare(a, b); } @@ -169,7 +182,7 @@ namespace BlackMisc * \ingroup Tuples */ template - QDBusArgument &operator <<(QDBusArgument &arg, std::tuple tu) + QDBusArgument &operator <<(QDBusArgument &arg, std::tuple tu) { return Private::TupleHelper::marshall(arg, tu); } @@ -179,7 +192,7 @@ namespace BlackMisc * \ingroup Tuples */ template - const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple tu) + const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple tu) { return Private::TupleHelper::unmarshall(arg, tu); } @@ -189,7 +202,7 @@ namespace BlackMisc * \ingroup Tuples */ template - uint qHash(std::tuple tu) + uint qHash(std::tuple tu) { return Private::TupleHelper::hash(tu); } @@ -219,19 +232,99 @@ namespace BlackMisc #else // !Q_COMPILER_VARIADIC_TEMPLATES + template + auto tie(T0 &&arg0) + -> decltype(std::make_tuple(Private::tieHelper(arg0))) + { + return std::make_tuple(Private::tieHelper(arg0)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3, T4 &&arg4) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3, T4 &&arg4, T5 &&arg5) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3, T4 &&arg4, T5 &&arg5, T6 &&arg6) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3, T4 &&arg4, T5 &&arg5, T6 &&arg6, T7 &&arg7) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6), Private::tieHelper(arg7))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6), Private::tieHelper(arg7)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3, T4 &&arg4, T5 &&arg5, T6 &&arg6, T7 &&arg7, T8 &&arg8) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6), Private::tieHelper(arg7), Private::tieHelper(arg8))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6), Private::tieHelper(arg7), Private::tieHelper(arg8)); + } + + template + auto tie(T0 &&arg0, T1 &&arg1, T2 &&arg2, T3 &&arg3, T4 &&arg4, T5 &&arg5, T6 &&arg6, T7 &&arg7, T8 &&arg8, T9 &&arg9) + -> decltype(std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6), Private::tieHelper(arg7), Private::tieHelper(arg8), Private::tieHelper(arg9))) + { + return std::make_tuple(Private::tieHelper(arg0), Private::tieHelper(arg1), Private::tieHelper(arg2), Private::tieHelper(arg3), Private::tieHelper(arg4), + Private::tieHelper(arg5), Private::tieHelper(arg6), Private::tieHelper(arg7), Private::tieHelper(arg8), Private::tieHelper(arg9)); + } + inline int compare(std::tuple<>, std::tuple<>) { return 0; } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { return Private::compareHelper<0>(a, b); } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -239,7 +332,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -248,7 +341,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -258,7 +351,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -269,7 +362,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -281,7 +374,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -294,7 +387,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -308,7 +401,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } @@ -323,7 +416,7 @@ namespace BlackMisc } template - int compare(std::tuple a, std::tuple b) + int compare(std::tuple a, std::tuple b) { int result; if ((result = Private::compareHelper<0>(a, b))) { return result; } diff --git a/src/blackmisc/tuple_private.h b/src/blackmisc/tuple_private.h index ddfefad4b..6e6336f55 100644 --- a/src/blackmisc/tuple_private.h +++ b/src/blackmisc/tuple_private.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace BlackMisc { @@ -77,6 +78,29 @@ namespace BlackMisc } //! @} + // Helper which returns a copy of its argument if it's a tuple, + // otherwise returns a reference to its argument. + //! \private + //! @{ + template + auto tieHelper(T &obj, std::false_type isTupleTag) -> std::reference_wrapper + { + Q_UNUSED(isTupleTag); + return obj; + } + template + auto tieHelper(T &obj, std::true_type isTupleTag) -> T + { + Q_UNUSED(isTupleTag); + return obj; + } + template + auto tieHelper(T &obj) -> decltype(tieHelper(obj, IsTuple())) + { + return tieHelper(obj, IsTuple()); + } + //! @} + #ifdef Q_COMPILER_VARIADIC_TEMPLATES // Applying operations to all elements in a tuple, using recursion