LUMIERA.clone/src/lib/multifact-arg.hpp
Ichthyostega b2b75fbe43 attempt to make factory invocation more evident in the code
...but the whole design looks still overengineered. See #388

- should get rid of the explicit specialisation
- always use a function signature and thus have arguments?
- why inheriting from the wrapper?
2014-09-08 03:37:41 +02:00

138 lines
4.9 KiB
C++

/*
MULTIFACT-ARG.hpp - variant of family-of-object factory, accepting fabrication arguments
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file multifact-arg.hpp
** Extension allowing the MultiFact to pass arguments to the fabrication.
** This extension is implemented by template specialisations and thus kicks in
** when specifying a <i>function signature</i> as factory "product type". The resulting
** factory class exposes a function call operator matching this signature, additionally
** expecting the ID (to select the specific fabrication function) as first parameter.
**
** @note the function signature used for this variant of MultiFact should specify
** the raw/base (interface) type of the produced objects as a return type.
** Depending on the used wrapper, the actual fabrication functions indeed
** should yield the product in a form suitable to be accepted by the
** wrapper. E.g., when building smart-ptrs, the fabrication function
** should actually deliver a raw pointer to a heap allocated object.
** @todo still way to convoluted design. We can do better //////////TICKET #388
**
** @see multifact-argument-test.cpp
** @see query-resolver.cpp usage example
** @see multifact.hpp standard case
*/
#ifndef LIB_MULTIFACT_ARG_H
#define LIB_MULTIFACT_ARG_H
#include "lib/multifact.hpp"
#include "lib/meta/function.hpp"
namespace lib {
namespace factory {
using lib::meta::Types;
using lib::meta::FunctionSignature;
using lib::meta::FunctionTypedef;
using std::function;
/**
* Extended MultiFact configuration for arbitrary fabrication functions.
* Contrary to the (simple) standard case, such fabrication functions
* take additional arguments on each invocation. These arguments need
* to be passed through by MultiFact. Moreover, the actual Wrapper
* used may require these fabrication functions to deliver their
* product in a specific form, e.g. as pointer or reference.
* Thus, we have to re-build the actual signature of the
* fabrication functions to be installed into MultiFact.
*/
template< typename SIG
, template<class> class Wrapper
>
struct FabWiring<function<SIG>, Wrapper>
: Wrapper<typename FunctionSignature<function<SIG> >::Ret>
{
typedef typename FunctionSignature<function<SIG> >::Args Args;
typedef typename FunctionSignature<function<SIG> >::Ret Element;
typedef typename Wrapper<Element>::PType WrappedProduct;
typedef typename Wrapper<Element>::RType FabProduct;
typedef typename FunctionTypedef<FabProduct, Args>::Sig SIG_Fab;
};
/**
* Variant of MultiFact, accepting an additional invocation argument.
* Similar to the (simple) standard case, this MultiFact specialisation
* allows to install suitable fabrication function(s) at runtime and
* will select the function to use on invocation based on the given ID.
* One additional argument will be passed on to this function.
* @todo with a bit more metaprogramming it would be possible to
* accept multiple arguments; maybe we'll need this later on.
*/
template< typename ELM, typename ARG
, typename ID
, template<class> class Wrapper
>
class MultiFact<ELM(ARG), ID, Wrapper>
: public MultiFact<function<ELM(ARG)>,ID,Wrapper>
{
typedef MultiFact<function<ELM(ARG)>,ID,Wrapper> _Base;
typedef typename _Base::Creator Creator;
public:
typedef typename _Base::Product Product;
Product
operator() (ID const& id, ARG arg)
{
Creator& func = this->selectProducer (id);
return this->wrap (func(arg));
}
Product
invokeFactory (ID const& id, ARG arg) ///< alias for the function operator
{
return this->operator() (id, arg);
}
};
} // namespace factory
// TODO is there some suitable standard configuration we could provide here??
} // namespace lib
#endif