ability to pick up the attribute type from the closure/functor
The actual trick to make it work is to use decltype on the function operator http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda/7943765#7943765 In addition, we now pick up the functor by template type and store it under that very type. For one, this cuts the size of the generated class by a factor of two. And it gives the compiler the ability to inline a closure as much as is possible, especially when the created Binder / Mutator lives in the same reference frame the closure taps into.
This commit is contained in:
parent
f45884975b
commit
f9d0d13501
3 changed files with 40 additions and 15 deletions
7
LICENSE
7
LICENSE
|
|
@ -15,6 +15,13 @@ For a copy of the GPL Version 2 see the file COPYING
|
||||||
in addition they are also dual-licensed under *CC-By-SA 3*
|
in addition they are also dual-licensed under *CC-By-SA 3*
|
||||||
|
|
||||||
|
|
||||||
|
- at various places, the implementation draws on solutions
|
||||||
|
and comments published at http://Stackoverflow.com[Stackoverflow] --
|
||||||
|
according to the http://stackexchange.com/legal[License Agreement] page,
|
||||||
|
any ``subscriber content'' on that site is provided under *CC-By-SA 3*..
|
||||||
|
We attribute significant usages of solutions published this way
|
||||||
|
in the doxygen comments of the relevant source code entities.
|
||||||
|
|
||||||
|
|
||||||
- Parts of the Implementation are heavily inspired by +
|
- Parts of the Implementation are heavily inspired by +
|
||||||
*The Loki Library* (C) 2001 by *Andrei Alexandrescu*
|
*The Loki Library* (C) 2001 by *Andrei Alexandrescu*
|
||||||
|
|
|
||||||
|
|
@ -135,26 +135,46 @@ namespace diff{
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template<class PAR, typename VAL>
|
/**
|
||||||
|
* Type rebinding helper to pick up the actual argument type.
|
||||||
|
* Works both for functors and for lambda expressions
|
||||||
|
* @remarks Solution proposed 10/2011 by \link http://stackoverflow.com/users/224671/kennytm user "kennytm" \endlink
|
||||||
|
* in this \link http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda/7943765#7943765
|
||||||
|
* answer on stackoverflow \endlink
|
||||||
|
*/
|
||||||
|
template<typename FUN>
|
||||||
|
struct _ClosureType
|
||||||
|
: _ClosureType<decltype(&FUN::operator())>
|
||||||
|
{ };
|
||||||
|
|
||||||
|
template<class C, class RET, class ARG>
|
||||||
|
struct _ClosureType<RET (C::*)(ARG) const>
|
||||||
|
{
|
||||||
|
typedef ARG ArgType;
|
||||||
|
typedef RET ReturnType;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class PAR, class CLO>
|
||||||
struct ChangeOperation
|
struct ChangeOperation
|
||||||
: PAR
|
: PAR
|
||||||
{
|
{
|
||||||
using Closure = function<void(VAL)>;
|
|
||||||
|
|
||||||
ID attribID_;
|
ID attribID_;
|
||||||
Closure change_;
|
CLO change_;
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
setAttribute (ID id, Attribute& newValue)
|
setAttribute (ID id, Attribute& newValue)
|
||||||
{
|
{
|
||||||
|
using ValueType = typename _ClosureType<CLO>::ArgType;
|
||||||
|
|
||||||
if (id == attribID_)
|
if (id == attribID_)
|
||||||
change_(newValue.get<VAL>());
|
change_(newValue.get<ValueType>());
|
||||||
|
|
||||||
else // delegate to other closures (Decorator-style)
|
else // delegate to other closures (Decorator-style)
|
||||||
PAR::setAttribute(id, newValue);
|
PAR::setAttribute(id, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangeOperation(ID id, Closure clo, PAR const& chain)
|
ChangeOperation(ID id, CLO clo, PAR const& chain)
|
||||||
: PAR(chain)
|
: PAR(chain)
|
||||||
, attribID_(id)
|
, attribID_(id)
|
||||||
, change_(clo)
|
, change_(clo)
|
||||||
|
|
@ -169,19 +189,17 @@ namespace diff{
|
||||||
: PAR(par)
|
: PAR(par)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
template<typename VAL>
|
template<class CLO>
|
||||||
using Change = ChangeOperation<PAR,VAL>;
|
using Change = ChangeOperation<PAR,CLO>;
|
||||||
template<typename VAL>
|
|
||||||
using Closure = typename Change<VAL>::Closure;
|
|
||||||
|
|
||||||
|
|
||||||
/* ==== binding API ==== */
|
/* ==== binding API ==== */
|
||||||
|
|
||||||
template<typename VAL>
|
template<typename CLO>
|
||||||
Builder<Change<VAL>>
|
Builder<Change<CLO>>
|
||||||
change (Literal attributeID, Closure<VAL> closure)
|
change (Literal attributeID, CLO closure)
|
||||||
{
|
{
|
||||||
return Change<VAL> (attributeID, closure, *this);
|
return Change<CLO> (attributeID, closure, *this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ namespace test{
|
||||||
string localData;
|
string localData;
|
||||||
auto mutator =
|
auto mutator =
|
||||||
TreeMutator::build()
|
TreeMutator::build()
|
||||||
.change<string>("data", [&](string val)
|
.change("data", [&](string val)
|
||||||
{
|
{
|
||||||
cout << "\"data\" closure received something "<<val<<endl;
|
cout << "\"data\" closure received something "<<val<<endl;
|
||||||
localData = val;
|
localData = val;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue