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*
|
||||
|
||||
|
||||
- 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 +
|
||||
*The Loki Library* (C) 2001 by *Andrei Alexandrescu*
|
||||
|
|
|
|||
|
|
@ -135,26 +135,46 @@ namespace diff{
|
|||
|
||||
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
|
||||
: PAR
|
||||
{
|
||||
using Closure = function<void(VAL)>;
|
||||
|
||||
ID attribID_;
|
||||
Closure change_;
|
||||
CLO change_;
|
||||
|
||||
virtual void
|
||||
setAttribute (ID id, Attribute& newValue)
|
||||
{
|
||||
using ValueType = typename _ClosureType<CLO>::ArgType;
|
||||
|
||||
if (id == attribID_)
|
||||
change_(newValue.get<VAL>());
|
||||
change_(newValue.get<ValueType>());
|
||||
|
||||
else // delegate to other closures (Decorator-style)
|
||||
PAR::setAttribute(id, newValue);
|
||||
}
|
||||
|
||||
ChangeOperation(ID id, Closure clo, PAR const& chain)
|
||||
ChangeOperation(ID id, CLO clo, PAR const& chain)
|
||||
: PAR(chain)
|
||||
, attribID_(id)
|
||||
, change_(clo)
|
||||
|
|
@ -169,19 +189,17 @@ namespace diff{
|
|||
: PAR(par)
|
||||
{ }
|
||||
|
||||
template<typename VAL>
|
||||
using Change = ChangeOperation<PAR,VAL>;
|
||||
template<typename VAL>
|
||||
using Closure = typename Change<VAL>::Closure;
|
||||
template<class CLO>
|
||||
using Change = ChangeOperation<PAR,CLO>;
|
||||
|
||||
|
||||
/* ==== binding API ==== */
|
||||
|
||||
template<typename VAL>
|
||||
Builder<Change<VAL>>
|
||||
change (Literal attributeID, Closure<VAL> closure)
|
||||
template<typename CLO>
|
||||
Builder<Change<CLO>>
|
||||
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;
|
||||
auto mutator =
|
||||
TreeMutator::build()
|
||||
.change<string>("data", [&](string val)
|
||||
.change("data", [&](string val)
|
||||
{
|
||||
cout << "\"data\" closure received something "<<val<<endl;
|
||||
localData = val;
|
||||
|
|
|
|||
Loading…
Reference in a new issue