Storing types in a non-template class?
Hi, I have a singleton class called InputRegistry. Before the class is used, the user must call: InputRegistry::Initialize(); I would like this function to take a parameter that defines the type of a critical section object, which is unknown at compile time (template). I need to store this type in my InputRegistry class so that the unknown critical section type can be constructed later. How can I do this without making InputRegistry a template class? If I make InputRegistry a template, that basically means I need to redesign the class, as the singleton pattern would not apply if it were a template class. I'm hoping boost can help here. Thanks in advance.
AMDG Robert Dailey wrote:
Hi,
I have a singleton class called InputRegistry. Before the class is used, the user must call:
InputRegistry::Initialize();
I would like this function to take a parameter that defines the type of a critical section object, which is unknown at compile time (template). I need to store this type in my InputRegistry class so that the unknown critical section type can be constructed later. How can I do this without making InputRegistry a template class? If I make InputRegistry a template, that basically means I need to redesign the class, as the singleton pattern would not apply if it were a template class.
I'm hoping boost can help here. Thanks in advance.
I would expect the solution to look something like this (warning untested)
struct critical_section_base {
virtual void lock() = 0;
virtual void unlock() = 0;
};
template<class T>
struct critical_section_wrapper {
public:
virtual void lock() { t.lock(); }
virtual void unlock() { t.unlock(); }
private:
T t;
};
class InputRegistry {
public:
template<class T>
static void Initialize() {
critical_section_generator =
boost::lambda::new_
Robert Dailey wrote:
I would like this function to take a parameter that defines the type of a critical section object, which is unknown at compile time (template). I need to store this type in my InputRegistry class so that the unknown critical section type can be constructed later.
Perhaps the newly-accepted Boost.Factory library could help? http://www.boost-consulting.com/vault/index.php?action=downloadfile&filename=factory.zip&directory=X-Files&
On Thu, Jan 24, 2008 at 02:22:19PM -0600, Robert Dailey wrote:
I have a singleton class called InputRegistry. Before the class is used, the user must call:
InputRegistry::Initialize();
I would like this function to take a parameter that defines the type of a critical section object, which is unknown at compile time (template).
I think you mean the type is unknown (unforeseen) at the time of writing the template code? Certainly all types of a template must be known at the time actual code is generated for it.
I need to store this type in my InputRegistry class so that the unknown critical section type can be constructed later. How can I do this without making InputRegistry a template class?
The first counterquestion that comes to mind is why would you want to do this? What if two calls to Instance() are made, passing different types? And why would you defer creation of the actual object? If you're just going to defer creation until it's actually used I strongly suggest you reconsider this constraint. You can define a creator "helper" class inside InputRegistry that constructs the right object for you. Use type-erasure to store an instance of that class as a member. Unfortunately, since you'll need a fixed function signature in your abstract helper class you need a known interface for the object. If you don't you can only "call forward", not return. This gets messy. class InputRegistry { // abstract creator: template< typename Callee_t > struct IMyFlexibleCreator { virtual void createAndCall( Callee_t & callee ) const = 0; }; // concrete creator: template< typename Callee_t, typename Object_t > struct MyFlexibleCreator : IMyFlexibleCreator< Callee_t > { /*override*/ void createAndCall( Callee_t & callee ) const { callee( Object_t() ); }; }; // some poor soul that gets called: struct GetNewObject { temlate< typename Object_t > void operator()( Object_t const& t ) { /* do something with t */ } }; // keep creator on heap by pointer to base: static boost::scoped_ptr< IMyFlexibleCreator< GetNewObject > > my_creator_; public: template< typename Object_t > void Instance( Object_t const& /*ignored*/ ) { my_creator_.reset( new MyFlexibleCreator< GetNewObject, Object_t > ); } void some_func() { // pre: my_creator_.get(); GetNewObject worker; my_creator_->createAndCall( worker ); } }; And now you have some Object_t in the GetNewObject operator() function, but you cannot store it in InputRegistry without type erasure anyway. And this requires explicit assumptions about Object_t's interface. Assumption you need to make sooner or later anyway. Rather than following an approach illustrated above, please explain what you're problem is and we can probably come up with a better solution than this. You mention design patterns below. Have you tried looking at Proxy, which can be used to build gatekeepers to access the singleton in a controller way?
If I make InputRegistry a template, that basically means I need to redesign the class, as the singleton pattern would not apply if it were a template class.
You're right, there's no way for other code to know the exact name of your singleton class. You could, however, introduce another holder class and let it keep a templetized version of you InputRegistry. As long as it has a stable interface... and it goes on. By the way, singleton is not a pattern but rather an anti-pattern. It kills modular design. Please be critical about all the stuff you find in GoF etc., it's not all blue skies and green fields.
I'm hoping boost can help here. Thanks in advance.
Boost doesn't help you per se. You might want to look into Alexandrescu's excellent book "Modern C++ Design". Ciao, Niels
participants (4)
-
Nat Goodspeed
-
Niels Aan de Brugh
-
Robert Dailey
-
Steven Watanabe