diff --git a/src/lib/muttifac.hpp b/src/lib/muttifac.hpp index 97f76a487..13134c390 100644 --- a/src/lib/muttifac.hpp +++ b/src/lib/muttifac.hpp @@ -41,9 +41,9 @@ ** \par Singleton generation ** For the very common situation of building a family of singleton objects, accessible by ID, ** there is a convenience shortcut: The nested MultiFact::Singleton template can be instantiated - ** within the context providing the objects (usually a static context). In itself a lib::Singleton - ** factory, it automatically registers the singleton access function as "fabrication" function - ** into a suitable MultiFact instance passed in as ctor parameter. + ** within the context providing the objects (usually a static context). In itself a lib::Depend + ** singleton factory, it automatically registers the singleton access function as "fabrication" + ** function into a suitable MultiFact instance passed in as ctor parameter. ** ** @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 @@ -55,7 +55,7 @@ ** wrapper invoke the fabrication function and handle the result properly. ** ** @see multifact-test.cpp - ** @see multifact-argument-test.cpp + ** @see multifact-singleton-test.cpp ** @see SingletonFactory */ @@ -106,22 +106,64 @@ namespace lib { * Wrapper taking ownership, * by wrapping into smart-ptr */ - template + template struct BuildRefcountPtr { - using RawType = typename std::remove_pointer::type; + using RawType = typename std::remove_pointer::type; using BareType = RawType *; using ResultType = std::shared_ptr; template ResultType - wrap (FUN create, ARGS... args) noexcept + wrap (FUN create, ARGS... args) { return ResultType (create(args...)); } }; + /** + * Policy: use a custom functor + * to finish the generated product + * @remarks the nested structure allows to define + * both the raw type and the wrapped type. + * On instantiation of the MultiFact, pass + * the nested Wrapper struct template param. + * @warning the RAW type must match the result type + * of the MultiFac SIG. Beware of passing + * references or pointers to local data. + */ + template + struct Build + { + template + struct Wrapper + { + using RawType = RAW; + using BareType = RAW; + using ResultType = TAR; + + using WrapFunc = std::function; + + void + defineFinalWrapper (WrapFunc&& fun) + { + this->wrapper_ = fun; + } + + template + ResultType + wrap (FUN create, ARGS&&... args) + { + return wrapper_(std::forward (create(args...))); + } + + private: + WrapFunc wrapper_; + }; + }; + + @@ -203,6 +245,8 @@ namespace lib { + /* === Main type === */ + /** * Factory for creating a family of objects by ID. * The actual factory functions are to be installed @@ -218,7 +262,7 @@ namespace lib { , template class Wrapper = PassAsIs > class MuttiFac - : FabConfig::WrapFunctor + : public FabConfig::WrapFunctor { using _Conf = FabConfig; using SIG_Fab = typename _Conf::SIG_Fab; diff --git a/tests/library/multifact-test.cpp b/tests/library/multifact-test.cpp index 699cb2955..f850e0159 100644 --- a/tests/library/multifact-test.cpp +++ b/tests/library/multifact-test.cpp @@ -209,7 +209,7 @@ namespace test{ TestFactory theFact; - // the first "production line" is wired to a free function + // set up the "production lines" by lambda theFact.defineProduction (ONE, [] { return new Implementation; }); theFact.defineProduction (TWO, [] { return new Implementation; }); theFact.defineProduction (THR, [] { return new Implementation; }); @@ -247,7 +247,7 @@ namespace test{ TestFactory theFact; - // the first "production line" is wired to a free function + // set up the "production lines" theFact.defineProduction (ONE, [](string ) { return new Implementation; }); theFact.defineProduction (TWO, [](string ) { return new Implementation("X"); }); theFact.defineProduction (THR, [](string id) { return new Implementation(id); }); @@ -287,6 +287,35 @@ namespace test{ void fed_a_custom_finishing_functor() { + using TestFactory = factory::MuttiFac::Wrapper>; + + TestFactory theFact; + + // Setup(1): each "production line" does a distinct calculation + theFact.defineProduction (ONE, [](int par) { return par; }); + theFact.defineProduction (TWO, [](int par) { return 2 * par; }); + theFact.defineProduction (THR, [](int par) { return par*par; }); + theFact.defineProduction (FOU, [](int par) { return 1 << par;}); + + // Setup(2): and a common "wrapper functor" finishes + // the output of the chosen "production line" + theFact.defineFinalWrapper([](int raw) { return raw + 1; }); + + CHECK (long(1 + 1) == theFact(ONE, 1)); + CHECK (long(1 + 2) == theFact(ONE, 2)); + CHECK (long(1 + 3) == theFact(ONE, 3)); + + CHECK (long(1 + 2) == theFact(TWO, 1)); + CHECK (long(1 + 4) == theFact(TWO, 2)); + CHECK (long(1 + 6) == theFact(TWO, 3)); + + CHECK (long(1 + 1) == theFact(THR, 1)); + CHECK (long(1 + 4) == theFact(THR, 2)); + CHECK (long(1 + 9) == theFact(THR, 3)); + + CHECK (long(1 + 2) == theFact(FOU, 1)); + CHECK (long(1 + 4) == theFact(FOU, 2)); + CHECK (long(1 + 8) == theFact(FOU, 3)); } };