As described in this thread
http://www.cplusplus.com/forum/general/143652/ I've realized a delegate factory
implementation for my IOC Container. For wrapping the required Delegates calls I've the following resover
template implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
// Define generic resolver template
template < class R>
class GenericResolver;
class Resolver
{
protected:
Resolver(){}
public:
virtual ~Resolver() = default;
template<typename R, typename ... ARGS>
std::shared_ptr<R> resolve(ARGS&& ... args) const
{
using derived_type = GenericResolver<R>;
auto rs = dynamic_cast< const derived_type& >(*this);
return rs.template run<ARGS...>(std::forward<ARGS>(args)...);
}
};
template <typename T>
class GenericResolver : public Resolver
{
public:
GenericResolver(std::shared_ptr<brDelegate> delegate)
:m_delegate(delegate){}
GenericResolver(std::shared_ptr<T> instance)
:m_instance(instance){}
virtual ~GenericResolver() = default;
template<typename ... ARGS>
std::shared_ptr<T> run(ARGS&& ... args) const
{
if(m_instance.get()){
return m_instance;
}
else{
return std::make_shared<T>(
m_delegate->run<T, ARGS...>(std::forward<ARGS>(args)...));
}
}
std::shared_ptr<brDelegate> getDelegate(void) const {
return m_delegate;
}
private:
std::shared_ptr<brDelegate> m_delegate = nullptr;
std::shared_ptr<T> m_instance = nullptr;
};
|
And here the call of the resolve from container:
1 2 3 4 5 6
|
template <typename T, typename ... ARGS>
inline std::shared_ptr<T> brIOCContainer::resolve(ARGS&& ... args) const
{
auto resolver = (iter->second)->getResolver();
return resolver->resolve<T, ARGS...>(std::forward<ARGS>(args)...);
}
|
This works fine and I could create delegates and resolve objects from IOC Container by request
the required type. Here is an example from my google-tests:
1 2 3 4 5 6 7 8 9 10 11 12
|
delegate = brDelegate::create<Car>
([] () -> Car { return Car("Mustang GT 500"); });
container.registerDelegate<Car>(delegate);
auto r3 = container.resolve<Car>();
ASSERT_NE(nullptr, r3);
ASSERT_EQ("Mustang GT 500", r3->getName());
auto r4 = container.resolve<Car>();
ASSERT_NE(nullptr, r4);
ASSERT_EQ("Mustang GT 500", r4->getName());
ASSERT_NE(r3, r4);
|
It's also possible to register a delegate by contract, replacing only
the registration line:
1 2 3 4
|
container.registerDelegateByContract<IVehicle, Car>(delegate);
auto r3 = container.resolve<Car>();
ASSERT_NE(nullptr, r3);
ASSERT_EQ("Mustang GT 500", r3->getName());
|
At this point the resolve works, if I use the concrete type definition.
But I also want to resolve the concrete type Car if I use the IVehicle
interface request (This is required at each implementation point, where
I don't know the concrete implementation).
|
auto r3 = container.resolve<IVehicle>();
|
But here the trouble starts. I could not work against an contract C,
while I need the concrete type T and ARGS to invoke the delegate call.
This call could not be compiled, while the pure virtual methods of the
interface IVehicle couldn't be resolved at this point:
|
m_delegate->run<T, ARGS...>(std::forward<ARGS>(args)...));
|
On the other hand, I could not extend the template definition by using
a contract type, because it's not always given ...
Has anyone an idea how I could archive this? Or is this impossible?