The Artima Developer Community
Sponsored Link

Articles Forum
Subscribing Template Classes with Object Factories in C++

6 replies on 1 page. Most recent reply: Sep 24, 2007 9:31 PM by John Torjo

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 6 replies on 1 page
Frank Sommers

Posts: 2642
Nickname: fsommers
Registered: Jan, 2002

Subscribing Template Classes with Object Factories in C++ Posted: Sep 14, 2007 2:40 PM
Reply to this message Reply
Advertisement
Object factories provide a useful abstraction for object construction. A special problem with object factories must be considered, however, when subscribing template classes with object factories. This article presents an overview of the "subscription problem" along with several solutions:

http://www.artima.com/cppsource/subscription_problem.html

What do you think of the techniques presented in the article?


Maxim Yanchenko

Posts: 2
Nickname: jazzer
Registered: Sep, 2007

Re: Subscribing Template Classes with Object Factories in C++ Posted: Sep 16, 2007 11:31 PM
Reply to this message Reply
I think preprocessor can help a lot in such tasks.

The code is very straightforward and looks almost exactly how you'd write it manually.
It also can work with any number of policies:

#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/enum.hpp>

#define S1 (NoHide)(TimeoutHidding)(CHP)
#define S2 (NoDefense)(BulletProofed)(ShellProofed)
#define S3 (Movable)(Stationary)
// etc.

#define REGISTER(r, policies) \
factory->subscribe(Radar<BOOST_PP_SEQ_ENUM(policies)>::ID(), \
createInstance<IRadar, Radar<BOOST_PP_SEQ_ENUM(policies)> >);

BOOST_PP_SEQ_FOR_EACH_PRODUCT(REGISTER, (S1)(S2)(S3)/*etc.*/)

Maxim Noah Khailo

Posts: 25
Nickname: mempko
Registered: Nov, 2004

Re: Subscribing Template Classes with Object Factories in C++ Posted: Sep 17, 2007 8:19 AM
Reply to this message Reply
This is off subject but my name is Maxim Khailo. Yanchenko, are you Ukrainian? I certainly am.

Maxim Yanchenko

Posts: 2
Nickname: jazzer
Registered: Sep, 2007

Re: Subscribing Template Classes with Object Factories in C++ Posted: Sep 17, 2007 9:08 AM
Reply to this message Reply
> This is off subject but my name is Maxim Khailo.
> Yanchenko, are you Ukrainian? I certainly am.
Hi tyozka :)
No, I'm Russian, but from Bryansk (so it's wild mixture of Russians, Ukrainians, Belorussians and whoever else lived there)

m limber

Posts: 3
Nickname: mlimber
Registered: Nov, 2006

Re: Subscribing Template Classes with Object Factories in C++ Posted: Sep 17, 2007 9:57 AM
Reply to this message Reply
Thanks for this. I'd note that there are several syntax errors herein (e.g., "FactorySubscriber_2<C, H1, H2, IPC, Factory, CMW:>:subscribe(f)" should have the ":" after the ">").

I have a perhaps complementary technique that gives automatic registration with Loki factories. Below is a simplified version to ease explanation and understanding that is built with Loki 0.1.6 and MS VC++ 2005.

The key is that each factory-creatable class inherits from my FactoryCreatablePolicy, which automatically registers it with the factory. It comes with a virtual destructor (see notes in the destructor), but considering that we're talking about a hierarchy of classes, the factory-creatable class probably already had a virtual table, so we're not added much.


#include "loki/Factory.h"
#include "loki/Singleton.h"
#include "loki/static_check.h"
#include "loki/TypeManip.h"

template
<
class AbstractClass,
class ConcreteClass,
class FactoryIDType
>
class FactoryCreatablePolicy
{
public:
static AbstractClass* Create()
{
// Verify that the given types are
// actually super and sub classes
LOKI_STATIC_CHECK(
LOKI_SUPERSUBCLASS( AbstractClass, ConcreteClass ),
types_are_not_super_and_subclass );

return new ConcreteClass;
}

// Method to allow non-conformant compilers
// to manually register with the factory.
// Only needed as a work-around.
static bool IsRegistered()
{ return registered_; }

protected:
// Protected ctor and dtor so base classes
// can use this as a policy
FactoryCreatablePolicy() {}

// "virtual" is required because otherwise the compiler
// may optimize this away, subverting the trick described
// below.
virtual ~FactoryCreatablePolicy()
{
// In order to automatically register with
// the factory any subclass that uses this
// class as a policy, we must force the
// instantiation of the static member
// registered_. Otherwise, it will not be
// instantiated unless the program explicitly
// references it somewhere, which is an
// inconvenient requirement. This way it will
// always be instantiated on a standard-
// conformant compiler.

(void)&registered_;
}

private:
// This typedef would need to be expanded to
// include all other factory parameters. It is
// reduced here for the sake of simplicity of
// presentation.

typedef Loki::SingletonHolder
<
Loki::Factory
<
AbstractClass,
FactoryIDType
>
> theFactory;

static const volatile bool registered_;
};

// Register all our factory-creatable classes
// with their respective factories. (Note that
// these static members appear in the header file
// because they are themselves templates. The
// compiler will ensure that there is only one
// instance of each globally.)
template
<
class AbstractClass,
class ConcreteClass,
class FactoryIDType
>
const volatile bool
FactoryCreatablePolicy<AbstractClass, ConcreteClass, FactoryIDType>::registered_ =
theFactory::Instance().Register(
ConcreteClass::FACTORY_ID,
Create );


Now some code to demonstrate what it does. Given a hierarchy of classes (here, a base with two derived classes), each class must define a class ID for the factory. I have used ints here for simplicity, but it could be strings or whatever.


struct Base
{
virtual ~Base() {}
};

struct Derived1
: Base
, FactoryCreatablePolicy<Base,Derived1,int>
{
enum { FACTORY_ID = 1 };
};

struct Derived2
: Base
, FactoryCreatablePolicy<Base,Derived2,int>
{
enum { FACTORY_ID = 2 };
};

typedef Loki::Factory<Base, int> BaseFactory;
typedef Loki::SingletonHolder< BaseFactory > theBaseFactory;

int main()
{
BaseFactory& factory =
theBaseFactory::Instance();

try
{
auto_ptr<Base> b1( factory.CreateObject( Derived1::FACTORY_ID ) );
auto_ptr<Base> b2( factory.CreateObject( Derived2::FACTORY_ID ) );

// ...

cout << "Successful creation of objects." << endl;
}
catch( const exception& e )
{
cerr << e.what() << endl;
return -1;
}
}


This might be compatible and incorporatable into what you've done here. I've also proposed that the Loki crew consider including code in Loki.

Cheers! --M

PS, Thanks to several folks on comp.lang.c++.moderated, especially James Kanze, for helping me work this out a bit.

Maxim Noah Khailo

Posts: 25
Nickname: mempko
Registered: Nov, 2004

Re: Subscribing Template Classes with Object Factories in C++ Posted: Sep 18, 2007 9:06 AM
Reply to this message Reply
> > This is off subject but my name is Maxim Khailo.
> > Yanchenko, are you Ukrainian? I certainly am.
> Hi tyozka :)
> No, I'm Russian, but from Bryansk (so it's wild mixture of
> Russians, Ukrainians, Belorussians and whoever else lived
> there)

I guess to be more specific, I am half Russian and half Ukrainian. The region I was born is was also a wild mix of Russians, Ukrainians and the like. However most people just call themselves Russian, and that is what I do.

I live in USA now and am excited to see anyone with the name "Maxim". Ha :-)

John Torjo

Posts: 2
Nickname: jtorjo
Registered: Sep, 2007

Re: Subscribing Template Classes with Object Factories in C++ Posted: Sep 24, 2007 9:31 PM
Reply to this message Reply
The article is great, but what it's trying to address, is pretty far fetched...

Do we really want this kind of bloat? Do we really want to register 81, 144, 256 factories? I mean, I'm all for templates - if you've read some of my articles, you should definitely know, but this is taken a bit to the extreme... On top of this, we could add pretty high compile times...

Unless for the very simple cases, where the templated class is very small, and the policies are trivial, I would definitely choose a different solution: for each type of policy, I would have a Delegater, which would probably use a smart pointer to the real policy. So, for instance, instead of 2 x 4 x 5 = 40 classes, I'd have 2 + 4 + 5 = 11 classes. Instead of 3 x 3 x 3 x 3 = 81, I'd have 3 + 3 + 3 + 3 = 12.

That's my 2 euro cents, anyway ;)

Best,
John

--
http://John.Torjo.com -- C++ expert
... call me only if you want things done right

Flat View: This topic has 6 replies on 1 page
Topic: Do Frameworks and APIs Limit Developers' Imagination? Previous Topic   Next Topic Topic: Continuations in Java

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use