enumBindMode{Invalid=0,Read=1,Write=2};//!< Specifies QBind::bind traversal and processing (the design would support other BindMode like Append or Diff)
//! QBind is a class of template functions binding a Val<TResult> with a T, returning the TResult
//! Its least specialized definition calls a T::bind method that is more convenient to define than a QBind specialization
//! 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
//!
//! Its least specialized definition calls a T::bind(Val<TResult>&&) method that is more convenient to define than a QBind specialization
//! \see Person::bind() definition in main.cpp for an example
//!
//! \remark bind is not a template function to avoid conflicts with ADL and allow more precise class specialization
//! \remark Val<> is a move-only type passed by rvalue reference following http://scottmeyers.blogspot.com/2014/07/should-move-only-types-ever-be-passed.html
//! \remark bind is more explicit than operator()
//! \remark bind is more explicit than operator() but could be changed to enable use as std::function
//! \remark QBind has a structure similar to a Traversable : https://wiki.haskell.org/Typeclassopedia#Traversable
//! 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
staticTResultbind(Val<TResult>&&value,T&t){returnt.bind(std::move(value));}// In case of error, define a T::bind(Val<TResult>) method or external QBind<TResult,T>::bind(Val<TResult>,T&)
...
...
@@ -146,18 +134,11 @@ struct QBind {
// - serializing, deserializing
// - constructing generic in-memory data structures
// - etc...
// See Person::bind() definition below for an example
#include <QtCore/qvector.h>
structBindNative{};
structBindGeneric{};
template<classTResult,typenameT,typenameTEnabledIf=void>structBindSupport:BindGeneric{};//!< Specifies whether Val calls TResult::_bind or QBind<TResult,T>::bind
template<classT_>classRec;//!< a Record data structure defined below
template<classT_>classSeq;//!< a Sequence data structure defined below
template<classT_>classVal//!< a choice of sequence(), record(), null(), or any value with a textual representation
template<classT_>classVal//!< a choice of sequence(), record(), null(), or any value with at least a textual representation and possibly binary ones
{
Q_DISABLE_COPY(Val)
public:
...
...
@@ -252,10 +233,27 @@ private:
T_outer=T_();
};
//! A non-owning pointer to TImpl that transparently bypasses invalid calls to TImpl
//! \remark Can be used to easily implement Reader/Writers adding shortcut methods using Cur((TImpl*)this)
//! \warning Cur bypasses calls to a nullptr==impl
//! \remark A nullptr==impl results from using the same intermediate Val/Seq/Rec twice (a programmer error) or from runtime impl errors
enumBindMode{Invalid=0,Read=1,Write=2};//!< Specifies QBind::bind traversal and processing (the design would support other BindMode like Append or Diff)
structBindGeneric{};
structBindNative{};
template<classTResult,typenameT,typenameTEnabledIf=void>structBindSupport:BindGeneric{};//!< Specifies whether Val calls TResult::_bind or QBind<TResult,T>::bind
// Base Cur<TImpl> implementations for Read and Write BindMode
...
...
@@ -313,7 +322,7 @@ private:
structIBind{
virtual~IBind()=default;
virtualBindModemode()const=0;
virtualBindModemode()const=0;//!< \remark a static constexpr BindMode Mode did not exhibit noticeable performance improvements and may trigger twice more code generation for Read/Write independant QBind like Person::bind
virtualbool_isOk()=0;//!< Current operation status
...
...
@@ -384,10 +393,12 @@ struct IBind {
virtualvoid_reportError(constchar*){}
};
usingCursor=Cur<IBind>;//!< \remark It would be possible to implement Cursor without templates nor BindSupport by defining all IBind overloads
//! 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 with a TResult which Mode == Write
//! 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
//! \warning a T&& may be allocated dynamically if its size exceeds compiler's Small Function Optimization
//! \warning copying should be forced using QWritable(T(t)) if QWritable::bind() must be called after t is destructed like when queued to another thread
template<classTResult>
classQWritable
//! \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<classTResult=Cursor>
classQBindable
{
std::function<TResult(Val<TResult>&&)>f;
public:
QWritable(){}
template<typenameT>QWritable(T&t):f(/*captured T ref */[&t](Val<TResult>&&v){returnv.bind(t);}){}
template<typenameT>QWritable(T&&t):f(/*captured T copy*/[t](Val<TResult>&&v){returnv.bind(t);}){}
QBindable(){}
template<typenameT>QBindable(T&t):f(/*captured T ref */[&t](Val<TResult>&&v){returnv.bind(t);}){}
template<typenameT>QBindable(T&&t):f(/*captured T copy*/[t](Val<TResult>&&v){returnv.bind(t);}){}