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:
Fischlurch 2015-05-03 05:24:06 +02:00
parent f45884975b
commit f9d0d13501
3 changed files with 40 additions and 15 deletions

View file

@ -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*

View file

@ -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);
}
};

View file

@ -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;