diff --git a/src/lib/muttifac.hpp b/src/lib/muttifac.hpp index aade9423b..97f76a487 100644 --- a/src/lib/muttifac.hpp +++ b/src/lib/muttifac.hpp @@ -178,7 +178,28 @@ namespace lib { using WrappedProduct = typename WrapFunctor::ResultType; typedef BareProduct SIG_Fab(void); + + enum{ ARGUMENT_CNT = 0 }; }; + /** + * @internal specialisation to deal with the generic case: + * using an arbitrary fabrication function with multiple arguments + */ + template< typename RET + , typename... ARGS + , template class Wrapper + > + struct FabConfig + { + using WrapFunctor = Wrapper; + using BareProduct = typename WrapFunctor::BareType; + using WrappedProduct = typename WrapFunctor::ResultType; + + typedef BareProduct SIG_Fab(ARGS...); + + enum{ ARGUMENT_CNT = sizeof...(ARGS)}; + }; + @@ -219,17 +240,33 @@ namespace lib { public: using Product = typename _Conf::WrappedProduct; + /** + * Core operation of the factory: + * Select a production line and invoke the fabrication function. + * @param id select the actual pre installed fabrication function to use + * @param args additional arguments to pass to the fabrication. + * @note the template parameter #SIG defines the raw or nominal signature + * of the fabrication, and especially the number of arguments + * @return the created product, after passing through the #Wrapper functor + */ + template Product - operator() (ID const& id) + operator() (ID const& id, ARGS&& ...args) { + static_assert (sizeof...(ARGS) == _Conf::ARGUMENT_CNT, + "MultiFac instance invoked with the wrong number " + "of fabrication arguments. See template parameter SIG"); + Creator& creator = selectProducer (id); - return this->wrap (creator); + return this->wrap (creator, std::forward(args)...); } + /** more legible alias for the function operator */ + template Product - invokeFactory (ID const& id) ///< alias for the function operator + invokeFactory (ID const& id, ARGS&& ...args) { - return this->operator() (id); + return this->operator() (id, std::forward(args)...); } diff --git a/tests/library/multifact-test.cpp b/tests/library/multifact-test.cpp index 86a29dd12..699cb2955 100644 --- a/tests/library/multifact-test.cpp +++ b/tests/library/multifact-test.cpp @@ -74,13 +74,17 @@ namespace test{ class Implementation : public Interface { + string instanceID_; + operator string() { - return "Impl-"+lexical_cast (ii); + return instanceID_ + lexical_cast (ii); } public: -// static theID getTypeID() { return ii; } + Implementation(string id = "Impl-") + : instanceID_(id) + { } }; @@ -239,6 +243,44 @@ namespace test{ void pass_additional_arguments() { + using TestFactory = factory::MuttiFac; + + TestFactory theFact; + + // the first "production line" is wired to a free function + theFact.defineProduction (ONE, [](string ) { return new Implementation; }); + theFact.defineProduction (TWO, [](string ) { return new Implementation("X"); }); + theFact.defineProduction (THR, [](string id) { return new Implementation(id); }); + theFact.defineProduction (FOU, [](string id) { return new Implementation("Z"+id);}); + + Interface *p1 = theFact(ONE, "irrelevant"), + *p2 = theFact(TWO, "ignored"), + *p3 = theFact(THR, "idiocy"), + *p4 = theFact(FOU, "omg"), + *p5 = theFact(FOU, "z"); + + // does not compile... + // theFact(ONE); + // theFact(ONE, "foo", bar); + + CHECK ("Impl-1" == string(*p1)); + CHECK ("X2" == string(*p2)); + CHECK ("idiocy3"== string(*p3)); + CHECK ("Zomg4" == string(*p4)); + CHECK ("Zz4" == string(*p5)); + + CHECK (!isSameObject(*p4, *p5)); + CHECK (INSTANCEOF(Implementation, p1)); + CHECK (INSTANCEOF(Implementation, p2)); + CHECK (INSTANCEOF(Implementation, p3)); + CHECK (INSTANCEOF(Implementation, p4)); + CHECK (INSTANCEOF(Implementation, p5)); + + delete p1; + delete p2; + delete p3; + delete p4; + delete p5; }