MultiFact: implement simple usage pattern. NOTE: breaks CLang 3.0

Implement the first simple usage scenario for the
unified MultiFact template, using variadic templates.

NOTE:
 - the obvious solution based on std::forward
   triggers strange behaviour in GCC-4.7
 - the inline lambda in the test case traps the
   CLang-3.0 parster with a segfault. Horay!
This commit is contained in:
Fischlurch 2014-09-13 02:50:14 +02:00
parent c209f2e80c
commit 0ff5c50030
2 changed files with 46 additions and 45 deletions

View file

@ -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 <functional>
#include <utility>
#include <memory>
#include <map>
@ -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<typename TAR>
struct PassReference
struct PassAsIs
{
typedef TAR& RType;
typedef TAR& PType;
typedef TAR ResultType;
PType wrap (RType object) { return object; }
template<class FUN, typename... ARGS>
ResultType
wrap (FUN create, ARGS... args) noexcept
{
return create(args...);
}
};
@ -95,10 +107,14 @@ namespace lib {
template<typename TAR>
struct BuildRefcountPtr
{
typedef TAR* RType;
typedef std::shared_ptr<TAR> PType;
typedef std::shared_ptr<TAR> ResultType;
PType wrap (RType ptr) { return PType{ptr}; }
template<class FUN, typename... ARGS>
ResultType
wrap (FUN create, ARGS... args) noexcept
{
return ResultType (create(args...));
}
};
@ -151,11 +167,12 @@ namespace lib {
template< typename TY
, template<class> class Wrapper
>
struct FabWiring
: Wrapper<TY>
struct FabConfig
{
typedef typename Wrapper<TY>::PType WrappedProduct;
typedef typename Wrapper<TY>::RType FabProduct;
using FabProduct = TY;
using WrapFunctor = Wrapper<TY>;
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> class Wrapper
, template<class> class Wrapper = PassAsIs
>
class MuttiFac
: public FabWiring<TY,Wrapper>
: FabConfig<SIG,Wrapper>::WrapFunctor
{
typedef FabWiring<TY,Wrapper> _Conf;
typedef typename _Conf::SIG_Fab SIG_Fab;
typedef Fab<SIG_Fab,ID> _Fab;
using _Conf = FabConfig<SIG,Wrapper>;
using SIG_Fab = typename _Conf::SIG_Fab;
using _Fab = Fab<SIG_Fab,ID>;
_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<typename FUNC>
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<TY,ID, factory::PassReference>
{ };
} // namespace lib
}} // namespace lib::factory
#endif

View file

@ -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<theID>, TWO));
// for the third "production line" we set up a function object
auto memberFunction = bind (&MultiFact_test::callMe, this, "lalü");