Commit 2d4ed500 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

Moved TResult and TImpl parameters in optional position with default

value where possible to demonstrate they are only useful to extend the
set of IBind native types
parent 88204d9f
......@@ -106,9 +106,12 @@ static QName qmSizes = "sizes" ; //!< comma-separated natural numbers
static QName qmChildren = "children"; //!< name of a sequence of records with recursively the same name
// //////////////////////////////////////////////////////////////////////////
// QBind<TResult,T>
// QBind<T,TResult>
template<class T_> class Val;
template<class T_> class Cur;
struct IBind;
using Cursor = Cur<IBind>; //!< \remark It would be possible to implement Cursor without templates nor BindSupport by defining all IBind overloads
//! QBind is a class of template methods binding T parts with Val<TResult> obeying a simple generic data model, and returning the TResult
//! Each QBind<_,T> should provide bind(T&&) and bind(T&) overloads for convenience and may provide bind(const T&) for performance depending on T
......@@ -123,11 +126,11 @@ template<class T_> class Val;
//! A QTraverse<Val<TResult>,T> would be equivalent but would not mandate to actually traverse T to get from Val<TResult> to the actual TResult
//! A QFold<TResult,T> would be equivalent to a Foldable allowing to fold T to any TResult without mandating a common Val/Seq structure
//!
template<class TResult, typename T, typename TEnabledIf=void>
template<typename T, class TResult=Cursor, typename TEnabledIf=void>
struct QBind {
static TResult bind(Val<TResult>&& value, T& t) { return t .bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<TResult,T>::bind(Val<TResult>,T&)
static TResult bind(Val<TResult>&& value,const T& t) { return const_cast<T&>(t).bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<TResult,T>::bind(Val<TResult>,const T&)
static TResult bind(Val<TResult>&& value, T&& t) { return t .bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<TResult,T>::bind(Val<TResult>,T&&)
static TResult bind(Val<TResult>&& value, T& t) { return t .bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<T,TResult>::bind(Val<TResult>,T&)
static TResult bind(Val<TResult>&& value,const T& t) { return const_cast<T&>(t).bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<T,TResult>::bind(Val<TResult>,const T&)
static TResult bind(Val<TResult>&& value, T&& t) { return t .bind(std::move(value)); } // In case of error, define a T::bind(Val<TResult>) method or external QBind<T,TResult>::bind(Val<TResult>,T&&)
};
//!< A pair of T value reference and defaultValue to use instead of null()
......@@ -155,7 +158,7 @@ public:
using TResult = typename T_::TResult; //!< the result of the traversal
operator bool() noexcept { return outer.operator bool(); } //!< Drives QBind<TResult,T>() traversal
operator bool() noexcept { return outer.operator bool(); } //!< Drives QBind<T>::bind() traversal
TResult* operator->() noexcept { return outer.operator ->(); }
/**/ Val<T_> meta ( QMetaData& m) { outer->_meta(m); return std::move(*this); }
......@@ -187,7 +190,7 @@ public:
// T_ can be either a TResult or any combination of nested Seq or Rec like Rec<Seq<TResult>
using TResult = typename T_::TResult;
operator bool() noexcept { return outer.operator bool(); } //!< Drives QBind<TResult,T>() traversal
operator bool() noexcept { return outer.operator bool(); } //!< Drives QBind<T>::bind() traversal
TResult* operator->() noexcept { return outer.operator ->(); }
TResult result() { return operator TResult(); }
operator TResult() { return out(); /* calls T_::operator TResult() if T_ != TResult */ }
......@@ -204,7 +207,7 @@ public:
/**/ Seq<T_> any ( ) { return item().any ( ); }
template<typename T> Seq<T_> bind ( T&& t) { return item().bind(std::forward<T>(t)); }
private:
template<class TResult, typename T, typename TEnabledIf> friend struct QBind;
template<typename T, class TResult, typename TEnabledIf> friend struct QBind;
Val<TResult> unsafeItem() noexcept { return outer->_item() ? Val<TResult>(outer._unsafeCopy()) : Val<TResult>(); }
T_ outer = T_();
......@@ -220,7 +223,7 @@ public:
// T_ can be either a TResult or any combination of nested Seq or Rec like Seq<Rec<TResult>
using TResult = typename T_::TResult;
operator bool() noexcept { return outer.operator bool(); } //!< Drives QBind<TResult,T>() traversal
operator bool() noexcept { return outer.operator bool(); } //!< Drives QBind<T>::bind() traversal
TResult* operator->() noexcept { return outer.operator ->(); }
TResult result() { return operator TResult(); }
operator TResult() { return out(); /* calls T_::operator TResult() if T_ != TResult */ }
......@@ -237,7 +240,7 @@ public:
/**/ Rec<T_> null (QName n ) { return item(n).null ( ); }
template<typename T> Rec<T_> bind (QName n, T&& t) { return item(n).bind(std::forward<T>(t)); }
private:
template<class TResult, typename T, typename TEnabledIf> friend struct QBind;
template<typename T, class TResult, typename TEnabledIf> friend struct QBind;
Val<TResult> unsafeItem(QUtf8String& n) noexcept { return outer->_item(n) ? Val<TResult>(outer._unsafeCopy()) : Val<TResult>(); }
T_ outer = T_();
......@@ -250,7 +253,7 @@ enum BindMode { Invalid=0, Read=1, Write=2 }; //!< Specifies QBind::bind travers
struct BindGeneric {};
struct BindNative {};
template<class TResult, typename T, typename TEnabledIf=void> struct BindSupport : BindGeneric {}; //!< Specifies whether Val calls TResult::_bind or QBind<TResult,T>::bind
template<typename T, class TImpl=IBind, typename TEnabledIf=void> struct BindSupport : BindGeneric {}; //!< Specifies whether Val calls TResult::_bind or QBind<T,TResult>::bind
#include <type_traits>
template<class T> using RemoveCvRef = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
......@@ -277,7 +280,7 @@ public:
BindMode mode() const noexcept { return impl ? impl->mode() : BindMode::Invalid; }
operator bool() noexcept { return impl && impl->_isOk(); } //!< Drives QBind<TResult,T>() traversal
operator bool() noexcept { return impl && impl->_isOk(); } //!< Drives QBind<T>::bind() traversal
Cur* operator ->() noexcept { return this; }
Val<Cur> value() noexcept { return Val<Cur>(std::move(*this)); }
......@@ -295,10 +298,10 @@ protected:
bool _null ( ) { return Q_LIKELY(impl) && impl->_null ( ); }
bool _any ( ) { return Q_LIKELY(impl) && impl->_any ( ); }
template<typename T> bool _bind( T&& t) { return _bind(BindSupport<TImpl,RemoveCvRef<T>>() ,std::forward<T>(t)); }
template<typename T> bool _bind( T&& t) { return _bind(BindSupport<RemoveCvRef<T>,TImpl>() ,std::forward<T>(t)); }
private:
template<typename T> bool _bind(BindNative , T&& t) { return Q_LIKELY(impl) && impl->_bind( std::forward<T>(t)); }
template<typename T> bool _bind(BindGeneric, T&& t) { return QBind<Cur,RemoveCvRef<T>>::bind(Val<Cur>(_unsafeCopy()),std::forward<T>(t)); }
template<typename T> bool _bind(BindGeneric, T&& t) { return QBind<RemoveCvRef<T>,Cur>::bind(Val<Cur>(_unsafeCopy()),std::forward<T>(t)); }
bool _item( QName n) { return Q_LIKELY(impl) && impl->_item(n); }
bool _item(QUtf8String& n) { return Q_LIKELY(impl) && impl->_item(n); }
......@@ -310,7 +313,7 @@ private:
TImpl* impl = nullptr;
};
template<class TResult>
template<class TResult=Cursor>
class QScopedChoice //!< for accurate error reporting
{
Q_DISABLE_COPY(QScopedChoice)
......@@ -328,7 +331,7 @@ private:
//#include <QtCore/qdatetime.h>
//#include <QtCore/quuid.h>
//! Interface for Cursor TImpl with a fixed subset of BindNative types and just a few optional methods
//! Interface for Cur's TImpl with a fixed subset of BindNative types and just a few optional methods
struct IBind {
virtual ~IBind() = default;
......@@ -403,29 +406,27 @@ struct IBind {
virtual void _reportError(const char*) {}
};
using Cursor = Cur<IBind>; //!< \remark It would be possible to implement Cursor without templates nor BindSupport by defining all IBind overloads
template<> struct BindSupport<IBind,const char*> : BindNative {};
template<> struct BindSupport<IBind,QUtf8String> : BindNative {};
template<> struct BindSupport<IBind, QString> : BindNative {};
//template<> struct BindSupport<IBind, QChar> : BindNative {};
template<> struct BindSupport<IBind, bool> : BindNative {};
template<> struct BindSupport<IBind, qint8> : BindNative {};
template<> struct BindSupport<IBind, quint8> : BindNative {};
template<> struct BindSupport<IBind, qint16> : BindNative {};
template<> struct BindSupport<IBind, quint16> : BindNative {};
template<> struct BindSupport<IBind, qint32> : BindNative {};
template<> struct BindSupport<IBind, quint32> : BindNative {};
template<> struct BindSupport<IBind, qint64> : BindNative {};
template<> struct BindSupport<IBind, quint64> : BindNative {};
//template<> struct BindSupport<IBind, qfloat16> : BindNative {};
template<> struct BindSupport<IBind, float> : BindNative {};
template<> struct BindSupport<IBind, double> : BindNative {};
//template<> struct BindSupport<IBind, QDate> : BindNative {};
//template<> struct BindSupport<IBind, QDateTime> : BindNative {};
//template<> struct BindSupport<IBind, QTime> : BindNative {};
//template<> struct BindSupport<IBind, QUuid> : BindNative {};
template<> struct BindSupport<IBind, QByteArray> : BindNative {};
template<> struct BindSupport<const char*> : BindNative {};
template<> struct BindSupport<QUtf8String> : BindNative {};
template<> struct BindSupport< QString> : BindNative {};
//template<> struct BindSupport< QChar> : BindNative {};
template<> struct BindSupport< bool> : BindNative {};
template<> struct BindSupport< qint8> : BindNative {};
template<> struct BindSupport< quint8> : BindNative {};
template<> struct BindSupport< qint16> : BindNative {};
template<> struct BindSupport< quint16> : BindNative {};
template<> struct BindSupport< qint32> : BindNative {};
template<> struct BindSupport< quint32> : BindNative {};
template<> struct BindSupport< qint64> : BindNative {};
template<> struct BindSupport< quint64> : BindNative {};
//template<> struct BindSupport< qfloat16> : BindNative {};
template<> struct BindSupport< float> : BindNative {};
template<> struct BindSupport< double> : BindNative {};
//template<> struct BindSupport< QDate> : BindNative {};
//template<> struct BindSupport< QDateTime> : BindNative {};
//template<> struct BindSupport< QTime> : BindNative {};
//template<> struct BindSupport< QUuid> : BindNative {};
template<> struct BindSupport< QByteArray> : BindNative {};
static char *qulltoa2(char *p, qulonglong n, int base=10)
{
......@@ -615,10 +616,10 @@ QAtomicPointer<IWriter> QLogger::s_impl = nullptr;
#include <functional>
//! A QBind<TResult,T> polymorphic in T (erased at compile-time) which is captured by reference or copy (for rvalue references) to be bound later
//! A QBind<T,TResult> polymorphic in T (erased at compile-time) which is captured by reference or copy (for rvalue references) to be bound later
//! \warning a T&& may be allocated dynamically if its size exceeds compiler's Small Function Optimization
//! \warning copying should be forced using QBindable(T(t)) if QBindable::bind() must be called after t is destructed like when queued to another thread for writing
template<class TResult = Cursor>
template<class TResult=Cursor>
class QBindable
{
std::function<TResult(Val<TResult>&&)> f;
......@@ -633,8 +634,8 @@ public:
// //////////////////////////////////////////////////////////////////////////
// QBind partial specializations (generic on TResult, usually not on v->mode() for dynamically-sized or builtin types)
template<class TResult, typename T>
struct QBind<TResult, QBindDefault<T>> {
template<typename T, class TResult> //=Cursor
struct QBind<QBindDefault<T>, TResult> {
static TResult bind(Val<TResult>&& v, QBindDefault<T>&& t) {
if (v->mode()==Read) {
auto r=v.null();
......@@ -650,8 +651,8 @@ struct QBind<TResult, QBindDefault<T>> {
}
};
template<class TResult, typename T>
struct QBind<TResult, T, typename std::enable_if<std::is_unsigned<T>::value && std::is_integral<T>::value && !std::is_same<T,bool>::value>::type> {
template<typename T, class TResult> //=Cursor
struct QBind<T, TResult, typename std::enable_if<std::is_unsigned<T>::value && std::is_integral<T>::value && !std::is_same<T,bool>::value>::type> {
static TResult bind(Val<TResult>&& v, T&& t) {
return v.bind(quint64(t));
}
......@@ -665,8 +666,8 @@ struct QBind<TResult, T, typename std::enable_if<std::is_unsigned<T>::value && s
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
}
};
template<class TResult, typename T>
struct QBind<TResult, T, typename std::enable_if<std::is_signed<T>::value && std::is_integral<T>::value && !std::is_same<T,bool>::value>::type> {
template<typename T, class TResult> //=Cursor
struct QBind<T, TResult, typename std::enable_if<std::is_signed<T>::value && std::is_integral<T>::value && !std::is_same<T,bool>::value>::type> {
static TResult bind(Val<TResult>&& v, T&& t) {
return v.bind(qint64(t));
}
......@@ -683,8 +684,8 @@ struct QBind<TResult, T, typename std::enable_if<std::is_signed<T>::value && std
// TODO QUrl, QRegularExpression, QMimeData, etc.
template<class TResult, typename T, unsigned Size>
struct QBind<TResult, T[Size]> {
template<typename T, unsigned Size, class TResult> //=Cursor
struct QBind<T[Size], TResult> {
static TResult bind(Val<TResult>&& v, T(& ts)[Size]) {
if (v->mode()==Write) {
quint32 size=Size;
......@@ -715,7 +716,7 @@ struct QBind<TResult, T[Size]> {
#include <QtCore/qstring.h>
template<class TResult> //=Cursor
struct QBind<TResult, QString> {
struct QBind<QString, TResult> {
static TResult bind(Val<TResult>&& v, QString&& s) {
return v.bind(s.toUtf8().constData());
}
......@@ -737,8 +738,8 @@ struct QBind<TResult, QString> {
#include <QtCore/qvector.h>
template<class TResult, typename T>
struct QBind<TResult, QVector<T>> {
template<typename T, class TResult> //=Cursor
struct QBind<QVector<T>, TResult> {
static TResult bind(Val<TResult>&& v, QVector<T>&& ts) {
if (v->mode()==Write) {
quint32 size=ts.size();
......@@ -775,8 +776,8 @@ struct QBind<TResult, QVector<T>> {
#include <QtCore/qlist.h>
template<class TResult, typename T>
struct QBind<TResult, QList<T>> {
template<typename T, class TResult> //=Cursor
struct QBind<QList<T>, TResult> {
static TResult bind(Val<TResult>&& v, QList<T>&& ts) {
if (v->mode()==Write) {
quint32 size=quint32(ts.size());
......@@ -808,8 +809,8 @@ struct QBind<TResult, QList<T>> {
#include <QtCore/qmap.h>
template<class TResult, typename T>
struct QBind<TResult, QMap<QString,T>> {
template<typename T, class TResult> //=Cursor
struct QBind<QMap<QString,T>, TResult> {
static TResult bind(Val<TResult>&& v, QMap<QString,T>&& ts) {
if (v->mode()==Write) {
quint32 size=quint32(ts.size());
......@@ -842,7 +843,7 @@ struct QBind<TResult, QMap<QString,T>> {
#include <QtGui/qcolor.h>
template<>
struct QBind<Cursor, QColor> {
struct QBind<QColor> {
static Cursor bind(Val<Cursor>&& v, QColor&& src) {
return v.record()
.bind("A",src.alpha())
......@@ -858,8 +859,8 @@ struct QBind<Cursor, QColor> {
// --------------------------------------------------------------------------
// QBind specialization for generic Val<Cursor> for a fixed set of possibly BindNative types
template<> //!< \remark Enumerating types where BindSupport<Cur<TImpl>,_> = BindNative with C++11 seems hard, so we just handle the set of default IBind BindNative types
struct QBind<Cursor, Val<Cursor>> {
template<> //!< \remark Enumerating types where BindSupport<_,Cur<TImpl>> = BindNative with C++11 seems hard, so we just handle the set of default IBind BindNative types
struct QBind<Val<Cursor>> {
static Cursor bind(Val<Cursor>&& src, Val<Cursor>&& dst) {
if (src->mode()==Read && dst->mode()==Write) {
Cursor srcRes;
......
......@@ -98,7 +98,7 @@ enum {
} // cbor
// //////////////////////////////////////////////////////////////////////////
// QBind<QCborWriter,T> support
// QBind<T,QCbor*> support
class QCborWriter : public IWriter
{
......@@ -312,8 +312,7 @@ private:
bool isChoice = false;
};
// //////////////////////////////////////////////////////////////////////////
// QBind<QCborValue,T> support
// --------------------------------------------------------------------------
#include <QtCore/qcborvalue.h>
#include <QtCore/qcborarray.h>
......
......@@ -47,7 +47,7 @@
#include "QBind_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<QDataStream*,T> support using operator<< for all registered types and containers, or GenericBind with DataTag
// QBind<T,QDataStream*> support using operator<< for all registered types and containers, or GenericBind with DataTag
static const char* qmDataStreamVersion = "qmDataStreamVersion";
......@@ -91,9 +91,9 @@ private:
QDataStream* io;
QString version;
};
template<typename T> struct BindSupport<QDataWriter,T> : BindSupport<IBind,T> {};
template<typename T> struct BindSupport<T,QDataWriter> : BindSupport<T> {};
// TODO BindNative other types that should bind specifically for compatibility with QDataStream
template<> struct BindSupport<QDataWriter, QColor> : BindNative {};
template<> struct BindSupport<QColor,QDataWriter> : BindNative {};
// --------------------------------------------------------------------------
......@@ -103,10 +103,10 @@ template<> struct BindSupport<QDataWriter, QColor> : BindNative {};
// And QDataStream version can be
// ///////////////////////////////////////////////////////////////////////////
// QBind<Cur<QDataWriter>,T> types that should bind specifically for compatibility with QDataStream
// QBind<T,Cur<QDataWriter>> types that should bind specifically for compatibility with QDataStream
template<>
struct QBind<Cur<QDataWriter>, QColor> {
struct QBind<QColor, Cur<QDataWriter>> {
static Cur<QDataWriter> bind(Val<Cur<QDataWriter>>&& v, QColor&& src) {
QMetaData m;
v=v.meta(m);
......
......@@ -50,7 +50,7 @@
#include "QBind_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<QJson*,T> support
// QBind<T,QJson*> support
class QJsonBuilder : public IWriter
{
......@@ -407,14 +407,14 @@ private:
};
// //////////////////////////////////////////////////////////////////////////
// QBind<_,QJson*> support
// QBind<QJson*,_> support
#include <QtCore/qjsonvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsonobject.h>
template<class TResult>
struct QBind<TResult, QJsonValue> {
template<class TResult> //=Cursor
struct QBind<QJsonValue, TResult> {
static TResult bind(Val<TResult>&& v, QJsonValue&& j) {
if (v->mode()==Write) {
if (j.isObject()) return v.bind(j.toObject());
......@@ -444,8 +444,8 @@ struct QBind<TResult, QJsonValue> {
}
};
template<class TResult>
struct QBind<TResult, QJsonArray> {
template<class TResult> //=Cursor
struct QBind<QJsonArray, TResult> {
static TResult bind(Val<TResult>&& v, QJsonArray&& j) {
if (v->mode()==Write) {
quint32 size=quint32(j.size());
......@@ -472,8 +472,8 @@ struct QBind<TResult, QJsonArray> {
}
};
template<class TResult>
struct QBind<TResult, QJsonObject> {
template<class TResult> //=Cursor
struct QBind<QJsonObject, TResult> {
static TResult bind(Val<TResult>&& v, QJsonObject&& j) {
if (v->mode()==Write) {
quint32 size=quint32(j.size());
......
......@@ -48,7 +48,7 @@
#include "QVariant_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<Q*Model,T> support
// QBind<T,Q*Model> support
class QModelWriter : public IWriter
{
......
......@@ -45,7 +45,7 @@
#include "QBind_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<QVariant*,T> support for the fixed set of QVariantBuilder's BindNative types
// QBind<T,QVariant*> support for the fixed set of QVariantBuilder's BindNative types
class QVariantBuilder : public IWriter
{
......@@ -130,13 +130,14 @@ private:
QStack<Step> steps = QStack<Step>();
bool isChoice = false;
};
// TODO BindNative other QVariant-supported types?
// //////////////////////////////////////////////////////////////////////////
// QBind<_,QVariant&> example support for the fixed set of IBind's BindNative types + other convenient types
// QBind<QVariant,_> example support for the fixed set of IBind's BindNative types + other convenient types
template<>
struct QBind<Cursor, QVariant> {
struct QBind<QVariant> {
static Cursor bind(Val<Cursor>&& v, QVariant&& src) {
if (v->mode()==Write) {
if (src.type()==QVariant::List ) return v.bind(src.value<QVariantList>()); // TODO QSequentialIterable ?
......@@ -155,7 +156,7 @@ struct QBind<Cursor, QVariant> {
if (src.type()==QVariant::Double ) return v.bind(src.value< double>());
// TODO convert builtin types which canConvert<QString>
// \sa QBind<TSrcResult, Val<TDst>&&, IsReader<TSrcResult>>
// \sa QBind<Val<TDst>&&, TSrcResult, IsReader<TSrcResult>>
return v.null();
}
......@@ -170,7 +171,7 @@ struct QBind<Cursor, QVariant> {
};
//template<>
//struct QBind<Cursor, QVariant&, IsReader<Cursor>> { static Cursor bind(Val<Cursor>&& v, QVariant& dst) {
//struct QBind<QVariant&, Cursor, IsReader<Cursor>> { static Cursor bind(Val<Cursor>&& v, QVariant& dst) {
// Cursor r;
// {
// QScopedChoice<Val<Cursor>> choice(src);
......
......@@ -40,16 +40,16 @@
// The core of QBind proof-of-concept including:
// - a fluent interface for describing logical data structures, providing auto completion and well-formedness guarantees
// - a set of recursive QBind<TResult,T> functors binding TResult and T according to their logical data structure
// - a set of recursive QBind<T,TResult> functors binding TResult and T according to their logical data structure
#include "QBind_impl.h"
// Extensible set of TResult implementations providing concrete syntax to the logical data structure in a specific Mode among Write, Read, ...
#include "QJson_impl.h" // QJsonWriter, QJsonReader, QJsonBuilder, QJsonVisitor and QBind<_,QJsonValue> support
#include "QJson_impl.h" // QJsonWriter, QJsonReader, QJsonBuilder, QJsonVisitor and QBind<QJsonValue,_> support
#include "QCbor_impl.h" // QCborWriter demonstrating the performance potential of the approach
#include "QData_impl.h" // QDataReader, QDataWriter demonstrating a QDataStream with implicit types for benchmarking
#include "QVariant_impl.h" // QVariantBuilder, QVariantVisitor and QBind<_,QVariant> support
#include "QVariant_impl.h" // QVariantBuilder, QVariantVisitor and QBind<QVariant,_> support
#include "QModel_impl.h" // Q*ModelWriter support
#include <QtCore/qvariant.h>
......@@ -60,13 +60,13 @@
#include <QtWidgets/qapplication.h>
// //////////////////////////////////////////////////////////////////////////
// QBind<_,T> basic example using an internal bind method
// QBind<T,_> basic example using an internal bind method
struct Person
{
QString firstName, lastName; double height; int age; QVector<QString> phones; QString comments;
template<class TResult>
template<class TResult> //=Cursor
TResult bind(Val<TResult>&& value) { // works with value->mode()==Read as well as Write
return value
.record()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment