Use of class factory in a recursive container

J

Johan Bergman

Hi,

Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

/ Johan
 
J

Johan Bergman

Hi,

I made a few typos in my first post so here it all comes again (corrected).

Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory_Base() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory_Base<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

/ Johan
 
V

Victor Bazarov

Johan Bergman said:
Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory_Base() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory_Base<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

You haven't shown how 'Array<>' uses the factory. For all we know,
the way it uses it should allow for "de-Array-fication". You could
write some kind of recursive template to "de-Array-fy" the template
argument until it reaches non-Array-derived type.

template<class T> class Array;

template<class T> class NonArray {
typedef T original;
};

// specialisation for 'Array<T>'
template<class T> class NonArray<Array<T> > {
typedef NonArray<T>::eek:riginal original; // recursive
};

template<class T> class Array {
typedef Factory_Base< NonArray<T>::eek:riginal > Real_Factory;
// use Real_Factory somehow
};

This is just a quick sketch, a nugde so to speak. Perhaps you can
dig something useful from it...

Victor
 
J

Johan Bergman

Victor Bazarov said:
Johan Bergman said:
Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory_Base() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory_Base<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

You haven't shown how 'Array<>' uses the factory.

Oops, you're right! My intention was to let Array<> call factory->create()
whenever it is supposed to create new (non-container) elements, i.e. when
the Array said:
For all we know,
the way it uses it should allow for "de-Array-fication". You could
write some kind of recursive template to "de-Array-fy" the template
argument until it reaches non-Array-derived type.

template<class T> class Array;

template<class T> class NonArray {
typedef T original;
};

// specialisation for 'Array<T>'
template<class T> class NonArray<Array<T> > {
typedef NonArray<T>::eek:riginal original; // recursive
};

template<class T> class Array {
typedef Factory_Base< NonArray<T>::eek:riginal > Real_Factory;
// use Real_Factory somehow
};

This is just a quick sketch, a nudge so to speak. Perhaps you can
dig something useful from it...

Yes, I think this helps a lot, thanks! (Perhaps you can recommend some good
books where I can learn more about this kind of C++ idioms?)

But now I have another problem. The Array<T> method that creates new
(container or non-container) elements should look something like this:

if (factory == 0)
// No factory was specified by the user
data = new T[n]; // line 3
else if (typeid(T) == typeid(Original))
// Time to use Real_Factory
data = factory->instantiate(n);
else
// T must be an Array of something
data = new T[n](*factory); // line 9

The library I am working on contains some Array<T> instantiations for types
T that don't have constructors that take a factory as a parameter. This
means that the compiler won't accept line 9 (although this line will never
be executed for such types because they will in practice be taken care of by
line 3). Is there any legal way to do this?

/ Johan
 
J

Johan Bergman

I made a typo again. In the post I just made I wrote create() in one place
an instantiate() in another place, but I meant the same function. Below you
will find a corrected version of the post.

/ Johan

Victor Bazarov said:
Johan Bergman said:
Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory_Base() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory_Base<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

You haven't shown how 'Array<>' uses the factory.

Oops, you're right! My intention was to let Array<> call factory->create()
whenever it is supposed to create new (non-container) elements, i.e. when
the Array said:
For all we know,
the way it uses it should allow for "de-Array-fication". You could
write some kind of recursive template to "de-Array-fy" the template
argument until it reaches non-Array-derived type.

template<class T> class Array;

template<class T> class NonArray {
typedef T original;
};

// specialisation for 'Array<T>'
template<class T> class NonArray<Array<T> > {
typedef NonArray<T>::eek:riginal original; // recursive
};

template<class T> class Array {
typedef Factory_Base< NonArray<T>::eek:riginal > Real_Factory;
// use Real_Factory somehow
};

This is just a quick sketch, a nudge so to speak. Perhaps you can
dig something useful from it...

Yes, I think this helps a lot, thanks! (Perhaps you can recommend some good
books where I can learn more about this kind of C++ idioms?)

But now I have another problem. The Array<T> method that creates new
(container or non-container) elements should look something like this:

if (factory == 0)
// No factory was specified by the user
data = new T[n]; // line 3
else if (typeid(T) == typeid(Original))
// Time to use Real_Factory
data = factory->create(n);
else
// T must be an Array of something
data = new T[n](*factory); // line 9

The library I am working on contains some Array<T> instantiations for types
T that don't have constructors that take a factory as a parameter. This
means that the compiler won't accept line 9 (although this line will never
be executed for such types because they will in practice be taken care of by
line 3). Is there any legal way to do this?

/ Johan
 
V

Victor Bazarov

Johan Bergman said:
I made a typo again. In the post I just made I wrote create() in one place
an instantiate() in another place, but I meant the same function. Below you
will find a corrected version of the post.

/ Johan

Victor Bazarov said:
Johan Bergman said:
Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory_Base() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory_Base<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

You haven't shown how 'Array<>' uses the factory.

Oops, you're right! My intention was to let Array<> call factory->create()
whenever it is supposed to create new (non-container) elements, i.e. when
the Array said:
For all we know,
the way it uses it should allow for "de-Array-fication". You could
write some kind of recursive template to "de-Array-fy" the template
argument until it reaches non-Array-derived type.

template<class T> class Array;

template<class T> class NonArray {
typedef T original;
};

// specialisation for 'Array<T>'
template<class T> class NonArray<Array<T> > {
typedef NonArray<T>::eek:riginal original; // recursive
};

template<class T> class Array {
typedef Factory_Base< NonArray<T>::eek:riginal > Real_Factory;
// use Real_Factory somehow
};

This is just a quick sketch, a nudge so to speak. Perhaps you can
dig something useful from it...

Yes, I think this helps a lot, thanks! (Perhaps you can recommend some good
books where I can learn more about this kind of C++ idioms?)

I recommend both "Modern C++ Design" by Alexandrescu and "C++ Templates"
by Vandevoorde and Josuttis. Very good books. Try the reverse order,
though. MC++D can be a bit too much.

Also, see Boost library for tons of template tricks. And monitor this
newsgroup. I've seen many interesting posts on templates.
But now I have another problem. The Array<T> method that creates new
(container or non-container) elements should look something like this:

if (factory == 0)
// No factory was specified by the user
data = new T[n]; // line 3
else if (typeid(T) == typeid(Original))
// Time to use Real_Factory
data = factory->create(n);
else
// T must be an Array of something
data = new T[n](*factory); // line 9

The library I am working on contains some Array<T> instantiations for types
T that don't have constructors that take a factory as a parameter. This
means that the compiler won't accept line 9 (although this line will never
be executed for such types because they will in practice be taken care of by
line 3). Is there any legal way to do this?

I don't know. My ability to write template code is still far from
advanced. I would probably try to specialise the 'create' function
based on 'T', which suggest that it should be a member template...

Victor
 
J

Johan Bergman

Thanks, your answers helped me a lot!

BR,
Johan

Victor Bazarov said:
Johan Bergman said:
I made a typo again. In the post I just made I wrote create() in one place
an instantiate() in another place, but I meant the same function. Below you
will find a corrected version of the post.

/ Johan

Victor Bazarov said:
Maybe someone can help me with this one. The following describes a
somewhat simplified version of my problem, but I think it will be
sufficient.

I want to use class factories (virtual constructors) which have this base
class:

template<class T>
class Factory_Base {
public:
virtual ~Factory_Base() {} // (could be pure virtual)
virtual T* create(int n) {return new T[n];} // (could be pure virtual)
};

I also have a container class, Array<T>, which has a constructor that
takes a factory as a parameter:

template<class T>
Array<T>::Array(Factory_Base<T> &f)
{
factory = &f; // Array<T> has a member Factory_Base<T> *factory
}

This works fine as long as I only want to do this:

My_Factory my_factory; // My_Factory creates My_T instances
Array<My_T> my_variable(my_factory);

However, sometimes I want to write like this:

My_Factory my_factory; // My_Factory still creates My_T instances
Array<Array<My_T> > my_variable(my_factory);

The most straightforward solution would be to create a factory that can
create Array<My_T>, but I don't want to do that.

Please tell me that there is another way!

You haven't shown how 'Array<>' uses the factory.

Oops, you're right! My intention was to let Array<> call factory->create()
whenever it is supposed to create new (non-container) elements, i.e. when
the Array said:
For all we know,
the way it uses it should allow for "de-Array-fication". You could
write some kind of recursive template to "de-Array-fy" the template
argument until it reaches non-Array-derived type.

template<class T> class Array;

template<class T> class NonArray {
typedef T original;
};

// specialisation for 'Array<T>'
template<class T> class NonArray<Array<T> > {
typedef NonArray<T>::eek:riginal original; // recursive
};

template<class T> class Array {
typedef Factory_Base< NonArray<T>::eek:riginal > Real_Factory;
// use Real_Factory somehow
};

This is just a quick sketch, a nudge so to speak. Perhaps you can
dig something useful from it...

Yes, I think this helps a lot, thanks! (Perhaps you can recommend some good
books where I can learn more about this kind of C++ idioms?)

I recommend both "Modern C++ Design" by Alexandrescu and "C++ Templates"
by Vandevoorde and Josuttis. Very good books. Try the reverse order,
though. MC++D can be a bit too much.

Also, see Boost library for tons of template tricks. And monitor this
newsgroup. I've seen many interesting posts on templates.
But now I have another problem. The Array<T> method that creates new
(container or non-container) elements should look something like this:

if (factory == 0)
// No factory was specified by the user
data = new T[n]; // line 3
else if (typeid(T) == typeid(Original))
// Time to use Real_Factory
data = factory->create(n);
else
// T must be an Array of something
data = new T[n](*factory); // line 9

The library I am working on contains some Array<T> instantiations for types
T that don't have constructors that take a factory as a parameter. This
means that the compiler won't accept line 9 (although this line will never
be executed for such types because they will in practice be taken care
of
by
line 3). Is there any legal way to do this?

I don't know. My ability to write template code is still far from
advanced. I would probably try to specialise the 'create' function
based on 'T', which suggest that it should be a member template...

Victor
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top