diff --git a/src/lib/muttifac.hpp b/src/lib/muttifac.hpp index d36ff81dd..c7233d499 100644 --- a/src/lib/muttifac.hpp +++ b/src/lib/muttifac.hpp @@ -45,9 +45,14 @@ ** factory, it automatically registers the singleton access function as "fabrication" function ** into a suitable MultiFact instance passed in as ctor parameter. ** - ** @note there is an extension header, multifact-arg.hpp, which provides template specialisations - ** for the special case when the fabrication functions need additional invocation arguments. - ** @todo still way to convoluted design. We can do better //////////TICKET #388 + ** @remarks this is the second attempt at building a skeleton of the core factory mechanics. + ** The first attempt was pre-C++11, relied on partial specialisations and was hard to + ** understand and maintain. In theory, with C++11 the task should be quite simple now, + ** relying on rvalue references and variadic templates. Unfortunately, as of 9/2014, + ** the compiler support is not yet robust enough on Debian/stable really to deal with + ** \em all the conceivable cases when forwarding arbitrary factory products. Thus + ** for now we choose to avoid the "perfect forwarding" problem and rather let the + ** wrapper invoke the fabrication function and handle the result properly. ** ** @see multifact-test.cpp ** @see multifact-argument-test.cpp @@ -64,6 +69,7 @@ #include "util.hpp" #include +#include #include #include @@ -76,15 +82,21 @@ namespace lib { /** * Dummy "wrapper", - * just returning a target-ref + * to perform the fabrication and return the unaltered product. + * @remarks this is a "perfect forwarding" implementation, + * similar to std::forward, used as policy template */ template - struct PassReference + struct PassAsIs { - typedef TAR& RType; - typedef TAR& PType; + typedef TAR ResultType; - PType wrap (RType object) { return object; } + template + ResultType + wrap (FUN create, ARGS... args) noexcept + { + return create(args...); + } }; @@ -95,10 +107,14 @@ namespace lib { template struct BuildRefcountPtr { - typedef TAR* RType; - typedef std::shared_ptr PType; + typedef std::shared_ptr ResultType; - PType wrap (RType ptr) { return PType{ptr}; } + template + ResultType + wrap (FUN create, ARGS... args) noexcept + { + return ResultType (create(args...)); + } }; @@ -151,11 +167,12 @@ namespace lib { template< typename TY , template class Wrapper > - struct FabWiring - : Wrapper + struct FabConfig { - typedef typename Wrapper::PType WrappedProduct; - typedef typename Wrapper::RType FabProduct; + using FabProduct = TY; + using WrapFunctor = Wrapper; + using WrappedProduct = typename WrapFunctor::ResultType; + typedef FabProduct SIG_Fab(void); }; @@ -171,22 +188,22 @@ namespace lib { * to be instantiated at the call site and acts as singleton factory, * accessible through a MultiFact instance as frontend. */ - template< typename TY + template< typename SIG , typename ID - , template class Wrapper + , template class Wrapper = PassAsIs > class MuttiFac - : public FabWiring + : FabConfig::WrapFunctor { - typedef FabWiring _Conf; - typedef typename _Conf::SIG_Fab SIG_Fab; - typedef Fab _Fab; + using _Conf = FabConfig; + using SIG_Fab = typename _Conf::SIG_Fab; + using _Fab = Fab; _Fab funcTable_; protected: - typedef typename _Fab::FactoryFunc Creator; + using Creator = typename _Fab::FactoryFunc; Creator& selectProducer (ID const& id) @@ -196,13 +213,13 @@ namespace lib { public: - typedef typename _Conf::WrappedProduct Product; + using Product = typename _Conf::WrappedProduct; Product operator() (ID const& id) { - Creator& func = this->selectProducer (id); - return this->wrap (func()); + Creator& creator = selectProducer (id); + return this->wrap (creator); } Product @@ -217,7 +234,7 @@ namespace lib { */ template void - defineProduction (ID id, FUNC fun) + defineProduction (ID id, FUNC&& fun) { funcTable_.defineProduction (id, fun); } @@ -257,21 +274,5 @@ namespace lib { - } // namespace factory - - - - /** - * Standard configuration of the family-of-object factory - * @todo this is rather guesswork... find out what the best and most used configuration could be.... - */ - template< typename TY - , typename ID - > - class MuttiFact - : public factory::MuttiFac - { }; - - -} // namespace lib +}} // namespace lib::factory #endif diff --git a/tests/library/multifact-test.cpp b/tests/library/multifact-test.cpp index 4db9d77bb..a6fab8c53 100644 --- a/tests/library/multifact-test.cpp +++ b/tests/library/multifact-test.cpp @@ -58,7 +58,7 @@ namespace test{ virtual operator string () =0; }; - inline ostream& operator<< (ostream& os, Interface& ifa) { return os << string(ifa); } +// inline ostream& operator<< (ostream& os, Interface& ifa) { return os << string(ifa); } enum theID @@ -146,7 +146,7 @@ namespace test{ theFact.defineProduction (ONE, buildOne); // second "production line" uses a explicit partial closure - theFact.defineProduction (TWO, bind (buildSome, TWO)); + theFact.defineProduction (TWO, bind (buildSome, TWO)); // for the third "production line" we set up a function object auto memberFunction = bind (&MultiFact_test::callMe, this, "lalü");