diff --git a/research/try.cpp b/research/try.cpp index 59acde5b4..dc1aca86d 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -23,41 +23,26 @@ // 11/11 - using the boost random number generator(s) // 12/11 - how to detect if string conversion is possible? // 1/12 - is partial application of member functions possible? +// 5/14 - c++11 transition: detect empty function object /** @file try.cpp - ** Research: perform a partial application of a member function. - ** The result of this partial application should be a functor expecting the remaining arguments. - ** The idea was to use this at various library functions expecting a functor or callback, so to - ** improve readability of the client code: clients could then just pass a member pointer, without - ** the need to use any tr1::bind expression. + ** Investigation: empty and unbound function objects. + ** Since \c std::function is bool convertible, it should be possible to detect an empty or + ** unbound functor object and record this state in a VTable. Actually this approach used to + ** work with tr1::function objects. But it ceased to work after switching to c++11 ** - ** \par Costs in code size - ** While this turned out to be possible, even without much work, just based on the existing - ** templates for partial functor application (function-closure.hpp), the resulting code size - ** is rather sobering. Especially in debug mode, quite some overhead is created, which makes - ** usage of this convenience feature in general purpose library code rather questionable. - ** When compiling with -O3 though, most of the overhead will be removed + ** The reason is the more concise meaning of \em convertibility with C++11 -- now, an + ** automatic conversion is required; thus what we need is rather the ability to \em construct + ** our target type from the given source explicitly, which is a weaker requirement. ** - ** The following numbers could be observed: - ** \code - ** debug / stripped // debug-O3 / stripped - ** just using a member pointer: 39013 / 7048 42061 / 7056 - ** using tr1::bind and function: 90375 / 15416 65415 / 9376 - ** partial apply, passing functor: 158727 / 23576 97479 / 11296 - ** partial apply with mem pointer: 119495 / 17816 78031 / 9440 - ** \endcode */ -#include "lib/meta/tuple.hpp" -#include "lib/meta/function-closure.hpp" - -//#include +#include +#include #include -using lib::meta::Types; -using lib::meta::Tuple; //using std::placeholders::_1; //using std::placeholders::_2; using std::function; @@ -68,96 +53,26 @@ using std::cout; using std::endl; -namespace lib { -namespace meta{ -namespace func{ - - -template -struct _PupS - { - typedef typename _Fun::Ret Ret; - typedef typename _Fun::Args::List Args; - typedef typename Splice::Front ArgsFront; - typedef typename Splice::Back ArgsBack; - typedef typename Types::Seq ArgsToClose; - typedef typename Types::Seq ArgsRemaining; - typedef typename _Sig::Type ReducedSignature; - - typedef function Function; - }; - -template -inline -typename _PupS::Function -papply (SIG f, A1 a1) +uint +funny (char c) { - typedef typename _PupS::ArgsToClose ArgsToClose; - typedef Tuple ArgTuple; - ArgTuple val(a1); - return PApply::bindFront (f, val); + return c; } -template -inline -typename _PupS::Function -papply (SIG f, A1 a1, A2 a2) -{ - typedef typename _PupS::ArgPrefix ArgsToClose; - typedef Tuple ArgTuple; - ArgTuple val(a1,a2); - return PApply::bindFront (f, val); -} - - -}}} // namespace lib::meta::func - -class Something - { - int i_; - - void - privateFun(char a) - { - char aa(a + i_); - cout << "Char-->" << aa < FunP; - - FunP - getBinding() - { -// function memf = bind (&Something::privateFun, _1, _2); -// return lib::meta::func::papply (memf, this); - return lib::meta::func::papply (&Something::privateFun, this); - } - -// typedef void (Something::*FunP) (char); -// -// FunP -// getBinding() -// { -// return &Something::privateFun; -// } - }; - - - - +using FUC = function; int main (int, char**) { - Something some(23); - Something::FunP fup = some.getBinding(); + FUC fun(funny); + FUC empty; - fup ('a'); + cout << "ASCII 'A' = " << fun('A'); + cout << " defined: " << bool(fun) + << " undefd; " << bool(empty) + << " bool-convertible: " << std::is_convertible::value + << " can build bool: " << std::is_constructible::value + << " bool from string: " << std::is_constructible::value; cout << "\n.gulp.\n"; diff --git a/src/lib/meta/function-erasure.hpp b/src/lib/meta/function-erasure.hpp index 203cc94d7..83f33c25e 100644 --- a/src/lib/meta/function-erasure.hpp +++ b/src/lib/meta/function-erasure.hpp @@ -116,7 +116,7 @@ namespace meta{ /** - * Policy for FunErasure: store an embedded tr1::function + * Policy for FunErasure: store an embedded std::function * Using this policy allows to store arbitrary complex functor objects * embedded within a neutral container and retrieving them later type-safe. * The price to pay is vtable access and heap storage of function arguments. diff --git a/src/lib/opaque-holder.hpp b/src/lib/opaque-holder.hpp index ce0cd6bd1..8a8e7433c 100644 --- a/src/lib/opaque-holder.hpp +++ b/src/lib/opaque-holder.hpp @@ -72,6 +72,7 @@ #include "lib/access-casted.hpp" #include "lib/util.hpp" +#include #include #include @@ -85,17 +86,20 @@ namespace lib { namespace { // implementation helpers... + using boost::enable_if; using boost::disable_if; - using boost::is_convertible; + using std::is_constructible; - bool - validitySelfCheck (bool boolConvertible) + template + typename enable_if< is_constructible, + bool >::type + validitySelfCheck (X const& boolConvertible) { - return boolConvertible; + return bool(boolConvertible); } template - typename disable_if< is_convertible, + typename disable_if< is_constructible, bool >::type validitySelfCheck (X const&) { diff --git a/tests/library/meta/function-erasure-test.cpp b/tests/library/meta/function-erasure-test.cpp index e57524137..11824da8e 100644 --- a/tests/library/meta/function-erasure-test.cpp +++ b/tests/library/meta/function-erasure-test.cpp @@ -252,13 +252,17 @@ namespace test { void detect_unboundFunctor (HOL h1, HOL h2, HOL h3) { - // fabricate an unbound functor... - + // fabricate a suitable, unbound functor to wrap... typedef typename BuildEmptyFunctor::Type NoFunc; NoFunc noFunction = NoFunc(); + + // wrap this (actually empty) functor into the holder type HOL emptyHolder (noFunction); + + // verify the older detects that the wrapped functor is empty CHECK (!emptyHolder); + // cross-verify that non-empty functors are not flagged as empty CHECK ( h1 ); CHECK ( h2 ); CHECK ( h3 );