MultiFact: how I learned to love the Bomb

C++11 is just incredibly cool. It is so easy to
support a flexible yet specific set of arguments
This commit is contained in:
Fischlurch 2014-09-14 02:06:58 +02:00
parent 372edbfc85
commit 932d49fd95
2 changed files with 85 additions and 6 deletions

View file

@ -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> class Wrapper
>
struct FabConfig<RET(ARGS...), Wrapper>
{
using WrapFunctor = Wrapper<RET>;
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<typename... ARGS>
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>(args)...);
}
/** more legible alias for the function operator */
template<typename... ARGS>
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>(args)...);
}

View file

@ -74,13 +74,17 @@ namespace test{
class Implementation
: public Interface
{
string instanceID_;
operator string()
{
return "Impl-"+lexical_cast<string> (ii);
return instanceID_ + lexical_cast<string> (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<Interface*(string), theID>;
TestFactory theFact;
// the first "production line" is wired to a free function
theFact.defineProduction (ONE, [](string ) { return new Implementation<ONE>; });
theFact.defineProduction (TWO, [](string ) { return new Implementation<TWO>("X"); });
theFact.defineProduction (THR, [](string id) { return new Implementation<THR>(id); });
theFact.defineProduction (FOU, [](string id) { return new Implementation<FOU>("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<ONE>, p1));
CHECK (INSTANCEOF(Implementation<TWO>, p2));
CHECK (INSTANCEOF(Implementation<THR>, p3));
CHECK (INSTANCEOF(Implementation<FOU>, p4));
CHECK (INSTANCEOF(Implementation<FOU>, p5));
delete p1;
delete p2;
delete p3;
delete p4;
delete p5;
}