mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-22 05:05:38 +08:00
refs #210 added Private::Attribute
* An Attribute contains a reference to a data member, plus some metadata * Creates the concept of a "meta tuple", a tuple of Attribute objects * New facilities in TupleConverterBase to be used inside the macro * Flags allow individual data members to be selectively enabled or disabled depending on how the tuple is used * Selective enable/disable is implemented by removing the indices of the flagged members from the index_sequence
This commit is contained in:
@@ -27,6 +27,8 @@ namespace BlackMisc
|
|||||||
{
|
{
|
||||||
QRegExp simple("^o\\.(\\w+)$");
|
QRegExp simple("^o\\.(\\w+)$");
|
||||||
if (member.contains(simple)) { m_names.push_back(simple.cap(1)); continue; }
|
if (member.contains(simple)) { m_names.push_back(simple.cap(1)); continue; }
|
||||||
|
QRegExp meta("^attr\\s*\\(\\s*o\\.(\\w+)");
|
||||||
|
if (member.contains(meta)) { m_names.push_back(meta.cap(1)); continue; }
|
||||||
qFatal("BLACK_DECLARE_TUPLE_CONVERSION: Parser couldn't extract member name from \"%s\"", qPrintable(member));
|
qFatal("BLACK_DECLARE_TUPLE_CONVERSION: Parser couldn't extract member name from \"%s\"", qPrintable(member));
|
||||||
}
|
}
|
||||||
for (auto &name : m_names) { name.remove(QRegExp("^m_")); }
|
for (auto &name : m_names) { name.remove(QRegExp("^m_")); }
|
||||||
|
|||||||
@@ -30,12 +30,16 @@
|
|||||||
* \details Put this macro outside of any namespace, in the same header as T, to make it usable in TupleConverter.
|
* \details Put this macro outside of any namespace, in the same header as T, to make it usable in TupleConverter.
|
||||||
* \param T The fully qualified name of the class.
|
* \param T The fully qualified name of the class.
|
||||||
* \param MEMBERS A parenthesized, comma-separated list of the data members of T, with each member prefixed by "o."
|
* \param MEMBERS A parenthesized, comma-separated list of the data members of T, with each member prefixed by "o."
|
||||||
* (the letter o followed by dot).
|
* (the letter o followed by dot). Can also use any types or functions inherited from TupleConverterBase.
|
||||||
* \par Example
|
* \par Example
|
||||||
* If class Things::MyThing has data members m_first, m_second, and m_third:
|
* If class Things::MyThing has data members m_first, m_second, and m_third:
|
||||||
* \code
|
* \code
|
||||||
* BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, o.m_third))
|
* BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, o.m_third))
|
||||||
* \endcode
|
* \endcode
|
||||||
|
* To disable m_third from participating in hash value generation:
|
||||||
|
* \code
|
||||||
|
* BLACK_DEFINE_TUPLE_CONVERSION(Things::MyThing, (o.m_first, o.m_second, attr(o.m_third, flags<DisabledForHash>())))
|
||||||
|
* \endcode
|
||||||
* \see BLACK_DECLARE_TUPLE_CONVERSION_TEMPLATE If T is a template, use this instead.
|
* \see BLACK_DECLARE_TUPLE_CONVERSION_TEMPLATE If T is a template, use this instead.
|
||||||
* \hideinitializer
|
* \hideinitializer
|
||||||
* \ingroup Tuples
|
* \ingroup Tuples
|
||||||
@@ -56,6 +60,16 @@
|
|||||||
{ \
|
{ \
|
||||||
return BlackMisc::tie MEMBERS; \
|
return BlackMisc::tie MEMBERS; \
|
||||||
} \
|
} \
|
||||||
|
static auto toMetaTuple(const T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
|
||||||
|
{ \
|
||||||
|
auto tu = BlackMisc::tieMeta MEMBERS; \
|
||||||
|
return tu; \
|
||||||
|
} \
|
||||||
|
static auto toMetaTuple(T &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
|
||||||
|
{ \
|
||||||
|
auto tu = BlackMisc::tieMeta MEMBERS; \
|
||||||
|
return tu; \
|
||||||
|
} \
|
||||||
static const Parser &parser() \
|
static const Parser &parser() \
|
||||||
{ \
|
{ \
|
||||||
static const Parser p(#MEMBERS); \
|
static const Parser p(#MEMBERS); \
|
||||||
@@ -94,6 +108,16 @@
|
|||||||
{ \
|
{ \
|
||||||
return BlackMisc::tie MEMBERS; \
|
return BlackMisc::tie MEMBERS; \
|
||||||
} \
|
} \
|
||||||
|
static auto toMetaTuple(const T<U...> &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
|
||||||
|
{ \
|
||||||
|
auto tu = BlackMisc::tieMeta MEMBERS; \
|
||||||
|
return tu; \
|
||||||
|
} \
|
||||||
|
static auto toMetaTuple(T<U...> &o) -> decltype(BlackMisc::tieMeta MEMBERS) \
|
||||||
|
{ \
|
||||||
|
auto tu = BlackMisc::tieMeta MEMBERS; \
|
||||||
|
return tu; \
|
||||||
|
} \
|
||||||
static const Parser &parser() \
|
static const Parser &parser() \
|
||||||
{ \
|
{ \
|
||||||
static const Parser p(#MEMBERS); \
|
static const Parser p(#MEMBERS); \
|
||||||
@@ -121,7 +145,36 @@ namespace BlackMisc
|
|||||||
*/
|
*/
|
||||||
class TupleConverterBase
|
class TupleConverterBase
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
//! \brief Metadata flags attached to tuple elements.
|
||||||
|
enum Flags
|
||||||
|
{
|
||||||
|
DisabledForComparison = 1 << 0, //!< Element will be ignored by compare(), but not by operators
|
||||||
|
DisabledForMarshalling = 1 << 1, //!< Element will be ignored during DBus marshalling
|
||||||
|
DisabledForDebugging = 1 << 2, //!< Element will be ignored when streaming to QDebug
|
||||||
|
DisabledForHashing = 1 << 3, //!< Element will be ignored by qHash()
|
||||||
|
DisabledForJson = 1 << 4 //!< Element will be ignored during JSON serialization
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
//! \brief A shorthand alias for passing flags as a compile-time constant.
|
||||||
|
template <quint64 F = 0>
|
||||||
|
using flags = std::integral_constant<quint64, F>;
|
||||||
|
|
||||||
|
//! \brief Create a tuple element with default metadata.
|
||||||
|
template <class T>
|
||||||
|
static Private::Attribute<T> attr(T &obj)
|
||||||
|
{
|
||||||
|
return { obj };
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \brief Create a tuple element with attached metadata.
|
||||||
|
template <class T, quint64 F>
|
||||||
|
static Private::Attribute<T, F> attr(T &obj, std::integral_constant<quint64, F>)
|
||||||
|
{
|
||||||
|
return { obj };
|
||||||
|
}
|
||||||
|
|
||||||
//! \brief Helper class which parses the stringified macro argument.
|
//! \brief Helper class which parses the stringified macro argument.
|
||||||
struct Parser
|
struct Parser
|
||||||
{
|
{
|
||||||
@@ -162,6 +215,15 @@ namespace BlackMisc
|
|||||||
static std::tuple<> constToTuple(const T &object);
|
static std::tuple<> constToTuple(const T &object);
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \name Static Private Member Functions
|
||||||
|
* \brief Returns a tuple of structs, each of which contains a reference to one of object's data members and its attched metadata.
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
static std::tuple<> toMetaTuple(const T &object);
|
||||||
|
static std::tuple<> toMetaTuple(T &object);
|
||||||
|
//! @}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \name Static Private Member Functions
|
* \name Static Private Member Functions
|
||||||
* \brief Returns an object with information extracted from the stringified macro argument.
|
* \brief Returns an object with information extracted from the stringified macro argument.
|
||||||
@@ -181,7 +243,7 @@ namespace BlackMisc
|
|||||||
using ::qHash;
|
using ::qHash;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Works like std::tie, and allows us to hook in our own customizations.
|
* \brief Works like std::tie, returning a tuple of references to just the values, with metadata removed.
|
||||||
* \ingroup Tuples
|
* \ingroup Tuples
|
||||||
*/
|
*/
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
@@ -190,6 +252,16 @@ namespace BlackMisc
|
|||||||
return std::make_tuple(Private::tieHelper(args)...);
|
return std::make_tuple(Private::tieHelper(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Works like std::tie, returning a tuple of objects, each of which contains metadata plus a reference to a value.
|
||||||
|
* \ingroup Tuples
|
||||||
|
*/
|
||||||
|
template <class... Ts>
|
||||||
|
auto tieMeta(Ts &&... args) -> decltype(std::make_tuple(Private::tieMetaHelper(args)...))
|
||||||
|
{
|
||||||
|
return std::make_tuple(Private::tieMetaHelper(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Lexicographical tuple comparison function which is CValueObject-aware.
|
* \brief Lexicographical tuple comparison function which is CValueObject-aware.
|
||||||
* \details Tuple members which are CValueObjects are compared using the compare() friend function of CValueObject;
|
* \details Tuple members which are CValueObjects are compared using the compare() friend function of CValueObject;
|
||||||
@@ -199,7 +271,10 @@ namespace BlackMisc
|
|||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
int compare(std::tuple<Ts...> a, std::tuple<Ts...> b)
|
int compare(std::tuple<Ts...> a, std::tuple<Ts...> b)
|
||||||
{
|
{
|
||||||
return Private::TupleHelper::compare(a, b, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valuesA = Private::stripMeta(a, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto valuesB = Private::stripMeta(b, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(a, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
return Private::TupleHelper::compare(valuesA, valuesB, Private::skipFlaggedIndices<TupleConverterBase::DisabledForComparison>(metaTu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -209,7 +284,9 @@ namespace BlackMisc
|
|||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
QDBusArgument &operator <<(QDBusArgument &arg, std::tuple<Ts...> tu)
|
QDBusArgument &operator <<(QDBusArgument &arg, std::tuple<Ts...> tu)
|
||||||
{
|
{
|
||||||
return Private::TupleHelper::marshall(arg, tu, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
return Private::TupleHelper::marshall(arg, valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForMarshalling>(metaTu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -219,7 +296,9 @@ namespace BlackMisc
|
|||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple<Ts...> tu)
|
const QDBusArgument &operator >>(const QDBusArgument &arg, std::tuple<Ts...> tu)
|
||||||
{
|
{
|
||||||
return Private::TupleHelper::unmarshall(arg, tu, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
return Private::TupleHelper::unmarshall(arg, valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForMarshalling>(metaTu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -229,7 +308,9 @@ namespace BlackMisc
|
|||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
QDebug operator <<(QDebug debug, std::tuple<Ts &...> tu)
|
QDebug operator <<(QDebug debug, std::tuple<Ts &...> tu)
|
||||||
{
|
{
|
||||||
return Private::TupleHelper::debug(debug, tu, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
return Private::TupleHelper::debug(debug, valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForDebugging>(metaTu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -250,7 +331,9 @@ namespace BlackMisc
|
|||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
uint qHash(std::tuple<Ts...> tu)
|
uint qHash(std::tuple<Ts...> tu)
|
||||||
{
|
{
|
||||||
return Private::TupleHelper::hash(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
return Private::TupleHelper::hash(valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForHashing>(metaTu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -261,18 +344,22 @@ namespace BlackMisc
|
|||||||
QJsonObject serializeJson(const QStringList &members, std::tuple<Ts...> tu)
|
QJsonObject serializeJson(const QStringList &members, std::tuple<Ts...> tu)
|
||||||
{
|
{
|
||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
Private::TupleHelper::serializeJson(json, members, tu, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
Private::TupleHelper::serializeJson(json, members, valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForJson>(metaTu));
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Convert from JSON to object
|
* \brief Convert from JSON to object
|
||||||
* \ingroup Tuples
|
* \ingroup Tuples
|
||||||
*/
|
*/
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple<Ts...> tu)
|
void deserializeJson(const QJsonObject &json, const QStringList &members, std::tuple<Ts...> tu)
|
||||||
{
|
{
|
||||||
Private::TupleHelper::deserializeJson(json, members, tu, Private::make_index_sequence<sizeof...(Ts)>());
|
auto valueTu = Private::stripMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
auto metaTu = Private::recoverMeta(tu, Private::make_index_sequence<sizeof...(Ts)>());
|
||||||
|
Private::TupleHelper::deserializeJson(json, members, valueTu, Private::skipFlaggedIndices<TupleConverterBase::DisabledForJson>(metaTu));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace BlackMisc
|
} // namespace BlackMisc
|
||||||
|
|||||||
@@ -55,13 +55,6 @@ namespace BlackMisc
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N, class Tu>
|
|
||||||
int compareHelper(const Tu &a, const Tu &b)
|
|
||||||
{
|
|
||||||
typedef typename std::decay<typename std::tuple_element<N, Tu>::type>::type Element;
|
|
||||||
return compareHelper(std::get<N>(a), std::get<N>(b), typename std::is_base_of<CValueObject, Element>::type());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our own implementation of std::index_sequence (because not implemented by MSVC2013)
|
// Our own implementation of std::index_sequence (because not implemented by MSVC2013)
|
||||||
template <size_t... Is>
|
template <size_t... Is>
|
||||||
struct index_sequence
|
struct index_sequence
|
||||||
@@ -82,12 +75,118 @@ namespace BlackMisc
|
|||||||
template <size_t C>
|
template <size_t C>
|
||||||
using make_index_sequence = typename GenSequence<0, C>::type;
|
using make_index_sequence = typename GenSequence<0, C>::type;
|
||||||
|
|
||||||
// Helper which will allow us to hook in our own customizations into BlackMisc::tie
|
// Create an index_sequence containing indices which match a given predicate.
|
||||||
|
template <class P, size_t I, size_t C, bool B = false, size_t I2 = 0xDeadBeef, size_t... Is>
|
||||||
|
struct GenSequenceOnPredicate;
|
||||||
|
template <class P, size_t I, size_t C, size_t I2, size_t... Is>
|
||||||
|
struct GenSequenceOnPredicate<P, I, C, true, I2, Is...>
|
||||||
|
{
|
||||||
|
static const bool test = P::template test<I>::value;
|
||||||
|
typedef typename GenSequenceOnPredicate<P, I + 1, C, test, I, Is..., I2>::type type;
|
||||||
|
};
|
||||||
|
template <class P, size_t I, size_t C, size_t I2, size_t... Is>
|
||||||
|
struct GenSequenceOnPredicate<P, I, C, false, I2, Is...>
|
||||||
|
{
|
||||||
|
static const bool test = P::template test<I>::value;
|
||||||
|
typedef typename GenSequenceOnPredicate<P, I + 1, C, test, I, Is...>::type type;
|
||||||
|
};
|
||||||
|
template <class P, size_t C, size_t I2, size_t... Is>
|
||||||
|
struct GenSequenceOnPredicate<P, C, C, true, I2, Is...>
|
||||||
|
{
|
||||||
|
typedef index_sequence<Is..., I2> type;
|
||||||
|
};
|
||||||
|
template <class P, size_t C, size_t I2, size_t... Is>
|
||||||
|
struct GenSequenceOnPredicate<P, C, C, false, I2, Is...>
|
||||||
|
{
|
||||||
|
typedef index_sequence<Is...> type;
|
||||||
|
};
|
||||||
|
template <class P>
|
||||||
|
using make_index_sequence_if = typename GenSequenceOnPredicate<P, 0, std::tuple_size<typename P::tuple_type>::value>::type;
|
||||||
|
|
||||||
|
// Predicates used with make_index_sequence_if.
|
||||||
|
template <quint64 F, class Tu>
|
||||||
|
struct FlagPresent
|
||||||
|
{
|
||||||
|
typedef Tu tuple_type;
|
||||||
|
template <size_t I>
|
||||||
|
struct test : std::integral_constant<bool, bool(std::tuple_element<I, Tu>::type::flags & F)> {};
|
||||||
|
};
|
||||||
|
template <quint64 F, class Tu>
|
||||||
|
struct FlagMissing
|
||||||
|
{
|
||||||
|
typedef Tu tuple_type;
|
||||||
|
template <size_t I>
|
||||||
|
struct test : std::integral_constant<bool, ! bool(std::tuple_element<I, Tu>::type::flags & F)> {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Combine make_index_sequence_if with predicates to get the indices of tuple elements with certain flags.
|
||||||
|
template <quint64 F, class Tu>
|
||||||
|
auto findFlaggedIndices(Tu &&) -> make_index_sequence_if<FlagPresent<F, typename std::decay<Tu>::type>>
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
template <quint64 F, class Tu>
|
||||||
|
auto skipFlaggedIndices(Tu &&) -> make_index_sequence_if<FlagMissing<F, typename std::decay<Tu>::type>>
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// A tuple element with attached metadata.
|
||||||
|
template <class T, quint64 Flags = 0>
|
||||||
|
struct Attribute
|
||||||
|
{
|
||||||
|
typedef T type;
|
||||||
|
static const quint64 flags = Flags;
|
||||||
|
|
||||||
|
Attribute(T &obj) : m_obj(obj) {}
|
||||||
|
T &m_obj;
|
||||||
|
|
||||||
|
bool operator ==(const Attribute &other) const { return m_obj == other.m_obj; }
|
||||||
|
bool operator !=(const Attribute &other) const { return m_obj != other.m_obj; }
|
||||||
|
bool operator <(const Attribute &other) const { return m_obj < other.m_obj; }
|
||||||
|
bool operator <=(const Attribute &other) const { return m_obj <= other.m_obj; }
|
||||||
|
bool operator >(const Attribute &other) const { return m_obj > other.m_obj; }
|
||||||
|
bool operator >=(const Attribute &other) const { return m_obj >= other.m_obj; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helpers used in tie(), tieMeta(), and elsewhere, which arrange for the correct types to be passed to std::make_tuple.
|
||||||
|
// See http://en.cppreference.com/w/cpp/utility/tuple/make_tuple
|
||||||
|
// "For each Ti in Types..., the corresponding type Vi in Vtypes... is std::decay<Ti>::type
|
||||||
|
// unless application of std::decay results in std::reference_wrapper<X>, in which case the deduced type is X&."
|
||||||
template <class T>
|
template <class T>
|
||||||
std::reference_wrapper<T> tieHelper(T &obj)
|
std::reference_wrapper<T> tieHelper(T &obj)
|
||||||
{
|
{
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
template <class T, quint64 Flags>
|
||||||
|
std::reference_wrapper<T> tieHelper(Attribute<T, Flags> attr)
|
||||||
|
{
|
||||||
|
return attr.m_obj;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
Attribute<T> tieMetaHelper(T &obj)
|
||||||
|
{
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
template <class T, quint64 Flags>
|
||||||
|
Attribute<T, Flags> tieMetaHelper(Attribute<T, Flags> attr)
|
||||||
|
{
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a meta tuple to a value tuple
|
||||||
|
template <class Tu, size_t... Is>
|
||||||
|
auto stripMeta(Tu &&tu, index_sequence<Is...>) -> decltype(std::make_tuple(tieHelper(std::get<Is>(std::forward<Tu>(tu)))...))
|
||||||
|
{
|
||||||
|
return std::make_tuple(tieHelper(std::get<Is>(std::forward<Tu>(tu)))...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a value tuple to a meta tuple with default metadata
|
||||||
|
template <class Tu, size_t... Is>
|
||||||
|
auto recoverMeta(Tu &&tu, index_sequence<Is...>) -> decltype(std::make_tuple(tieMetaHelper(std::get<Is>(std::forward<Tu>(tu)))...))
|
||||||
|
{
|
||||||
|
return std::make_tuple(tieMetaHelper(std::get<Is>(std::forward<Tu>(tu)))...);
|
||||||
|
}
|
||||||
|
|
||||||
// Applying operations to all elements in a tuple, using index_sequence for clean recursion
|
// Applying operations to all elements in a tuple, using index_sequence for clean recursion
|
||||||
class TupleHelper
|
class TupleHelper
|
||||||
|
|||||||
Reference in New Issue
Block a user