Boost logo

Boost Users :

From: Niels Aan de Brugh (nielsadb_at_[hidden])
Date: 2008-01-24 16:25:39


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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net