We use a system based around std::tuple
to attach declarative metadata
to the data members of value classes. The intention is to minimize the
number of places where the data members must be listed. Without this
system, each class would need separate lists of its data members for
operator<
, operator==
, stringification, streaming to DBus, streaming
to JSON, etc. The tuple system maintains one list of members for each
class, with optional metadata, and the methods can refer back to this
one list.
In order for a class or class template to use the tuple system, it must
include the BLACK_ENABLE_TUPLE_CONVERSION
macro somewhere in its
private:
section. The macro expects one argument: the name of the
class or class template.
The list of data members is placed in the same header file, outside of
any namespace, using the BLACK_DECLARE_TUPLE_CONVERSION
macro. The
macro expects two arguments: first, the fully qualified name of the
class or class template; second, a parenthesized, comma-separated list
of expressions, each one identifying a different data member. The
expected syntax of these expressions is described below, under
"Attribute Expressions".
To refer back to this list in a function implementation, call
TupleConverter<T>::toMetaTuple(*this)
, where T
is the name of the
class or class template. This returns a std::tuple
of reference
wrappers of the data members of *this
, which can be operated on by
various free functions; standard C++ already provides overloaded
comparison operators for std::tuple
which perform lexicographical
comparisons of the elements, and blackmisc/tuple.h
defines several
more, for streaming std::tuple
element-by-element to DBus, JSON, etc.
Only member functions of T
may call TupleConverter<T>::toMetaTuple
,
otherwise this would break encapsulation.
Each item in the parenthesized, comma-separated list of data members is
a C++ expression following a certain format. The permitted format is
composed of the functions and types defined in TupleConverterBase
.
In the expression, o
is the object of type T
which was passed as the
argument to toMetaTuple
. The simplest possible attribute expression is
just o.m_foo
, where m_foo
is the name of a data member of T
. This
expression will result in the data member being entered into the list of
tuple elements with default metadata attached.
Metadata can be added to an element through the attr
function.
attr(o.m_foo)
is identical to o.m_foo
; metadata is added by passing
additional arguments to the attr
function.
These are the kinds of metadata which can be attached to the tuple elements:
DisabledForDBus
will cause the member to be ignored when streaming to DBus. The default flags is zero, meaning that a member with default metadata will participate in all operations using toMetaTuple
.m_
prefix removed.BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::CFoo, (
o.m_apple, // default metadata
attr(o.m_orange, "lemon"), // with explicit JSON name
attr(o.m_banana, flags<DisabledForHashing>()) // with a flag
))
In this example, m_apple
has default metadata, m_orange
has a JSON
name of lemon
, and m_banana
will not participate in hashing.
The following functions are provided for API compatibility with an earlier version of the tuple system:
TupleConverter<T>::toTuple
toMetaTuple
, but it ignores all metadata.TupleConverter<T>::jsonMembers
QStringList
of the JSON names of all the members. This is no longer necessary when using toMetaTuple
.