How can I use a non-trivial constructor with as little code duplicationas possible?

W

William Payne

Hello, consider the following two classes (parent and child):

#ifndef SINGLETON_HPP
#define SINGLETON_HPP

#include <cstddef> /* NULL */

template <typename T>
class Singleton
{
public:
static T* get_instance()
{
if(!t)
{
t = new T;
}

return t;
}

private:
Singleton()
{
; /* Never reached. */
}

static T* t;
};

class int_singleton : public Singleton<int>
{
};

/* As with member functions of class templates, the definition must *
* be in the class header. When compilers properly support the export *
* keyword, definitions of member functions and static data members *
* can be moved to an implementation (.cpp) file. */
template <typename T>
T* Singleton<T>::t = NULL;

#endif /* #ifndef SINGLETON_HPP */

The int_singleton class is just an example, I will be using other
(user-defined classes) types in the "real application" (if I can make it
work).

If you look at Singleton::get_instance(), you see that when !t is true
it creates a new object of type T using the constructor that takes no
arguments. However, I need to use constructors that take several
arguments. How should I accomplish this so I get as little code
duplication as possible? I have several rather complex classes in my
program that, and there must be only one instance of each class at all
times, and I would like to use the base class Singleton as much as
possible. Maybe get_instance() should call a virtual create_object()
function when !t is true, a function I redefine in my subclasses?

Comments please, how should I solve this?

/ WP
 
V

Victor Bazarov

William said:
Hello, consider the following two classes (parent and child):

#ifndef SINGLETON_HPP
#define SINGLETON_HPP

#include <cstddef> /* NULL */

template <typename T>
class Singleton
{
public:
static T* get_instance()
{
if(!t)
{
t = new T;
}

return t;
}

private:
Singleton()
{
; /* Never reached. */
}

static T* t;
};

class int_singleton : public Singleton<int>
{
};

/* As with member functions of class templates, the definition must *
* be in the class header. When compilers properly support the export *
* keyword, definitions of member functions and static data members *
* can be moved to an implementation (.cpp) file. */
template <typename T>
T* Singleton<T>::t = NULL;

#endif /* #ifndef SINGLETON_HPP */

The int_singleton class is just an example, I will be using other
(user-defined classes) types in the "real application" (if I can make it
work).

If you look at Singleton::get_instance(), you see that when !t is true
it creates a new object of type T using the constructor that takes no
arguments. However, I need to use constructors that take several
arguments. How should I accomplish this so I get as little code
duplication as possible? I have several rather complex classes in my
program that, and there must be only one instance of each class at all
times, and I would like to use the base class Singleton as much as
possible. Maybe get_instance() should call a virtual create_object()
function when !t is true, a function I redefine in my subclasses?

Comments please, how should I solve this?

My approach would be something like policy-based design of your
"Singleton" class. There should be construction policies from which
the developer can pick when it derives its specific singleton from
your template.

template<class T> struct DefaultConstructionPolicy
{
static T *get() { return new T(); }
};

template<class T, T t_def> struct ValueConstrutionPolicy
{
static T *get() { return new T(t_def); }
};

template<class T, template <class> ConstructionPolicy>
class Singleton
{
static T* get_instance()
{
return ConstructionPolicy<T>::get();
}
};

class int_singleton : public Singleton<int, IntZeroConstructionPolicy>
{
};

class int_42_singleton : public Singleton<int,
{
};

[I didn't compile any of this, please take it as a hint only, not as
real code]

Victor
 
W

William Payne

Victor said:
William said:
Hello, consider the following two classes (parent and child):

#ifndef SINGLETON_HPP
#define SINGLETON_HPP

#include <cstddef> /* NULL */

template <typename T>
class Singleton
{
public:
static T* get_instance()
{
if(!t)
{
t = new T;
}

return t;
}

private:
Singleton()
{
; /* Never reached. */
}

static T* t;
};

class int_singleton : public Singleton<int>
{
};

/* As with member functions of class templates, the definition must *
* be in the class header. When compilers properly support the export *
* keyword, definitions of member functions and static data members *
* can be moved to an implementation (.cpp) file. */
template <typename T>
T* Singleton<T>::t = NULL;

#endif /* #ifndef SINGLETON_HPP */

The int_singleton class is just an example, I will be using other
(user-defined classes) types in the "real application" (if I can make
it work).

If you look at Singleton::get_instance(), you see that when !t is true
it creates a new object of type T using the constructor that takes no
arguments. However, I need to use constructors that take several
arguments. How should I accomplish this so I get as little code
duplication as possible? I have several rather complex classes in my
program that, and there must be only one instance of each class at all
times, and I would like to use the base class Singleton as much as
possible. Maybe get_instance() should call a virtual create_object()
function when !t is true, a function I redefine in my subclasses?

Comments please, how should I solve this?


My approach would be something like policy-based design of your
"Singleton" class. There should be construction policies from which
the developer can pick when it derives its specific singleton from
your template.

template<class T> struct DefaultConstructionPolicy
{
static T *get() { return new T(); }
};

template<class T, T t_def> struct ValueConstrutionPolicy
{
static T *get() { return new T(t_def); }
};

template<class T, template <class> ConstructionPolicy>
class Singleton
{
static T* get_instance()
{
return ConstructionPolicy<T>::get();
}
};

class int_singleton : public Singleton<int, IntZeroConstructionPolicy>
{
};

class int_42_singleton : public Singleton<int,
{
};

[I didn't compile any of this, please take it as a hint only, not as
real code]

Victor

Thanks for the quick reply, Victor! A bit more advanced than my attempt,
an attempt that ended in me noticing that a function can't be both
static and virtual. =(
I don't fully understand yet how I should use your design with my rather
complex classes. But I want to understand so I can use it!

/ WP
 
W

William Payne

William said:
Victor said:
William said:
Hello, consider the following two classes (parent and child):

#ifndef SINGLETON_HPP
#define SINGLETON_HPP

#include <cstddef> /* NULL */

template <typename T>
class Singleton
{
public:
static T* get_instance()
{
if(!t)
{
t = new T;
}

return t;
}

private:
Singleton()
{
; /* Never reached. */
}

static T* t;
};

class int_singleton : public Singleton<int>
{
};

/* As with member functions of class templates, the definition must *
* be in the class header. When compilers properly support the export *
* keyword, definitions of member functions and static data members *
* can be moved to an implementation (.cpp) file. */
template <typename T>
T* Singleton<T>::t = NULL;

#endif /* #ifndef SINGLETON_HPP */

The int_singleton class is just an example, I will be using other
(user-defined classes) types in the "real application" (if I can make
it work).

If you look at Singleton::get_instance(), you see that when !t is
true it creates a new object of type T using the constructor that
takes no arguments. However, I need to use constructors that take
several arguments. How should I accomplish this so I get as little
code duplication as possible? I have several rather complex classes
in my program that, and there must be only one instance of each class
at all times, and I would like to use the base class Singleton as
much as possible. Maybe get_instance() should call a virtual
create_object() function when !t is true, a function I redefine in my
subclasses?

Comments please, how should I solve this?



My approach would be something like policy-based design of your
"Singleton" class. There should be construction policies from which
the developer can pick when it derives its specific singleton from
your template.

template<class T> struct DefaultConstructionPolicy
{
static T *get() { return new T(); }
};

template<class T, T t_def> struct ValueConstrutionPolicy
{
static T *get() { return new T(t_def); }
};

template<class T, template <class> ConstructionPolicy>
class Singleton
{
static T* get_instance()
{
return ConstructionPolicy<T>::get();
}
};

class int_singleton : public Singleton<int, IntZeroConstructionPolicy>
{
};

class int_42_singleton : public Singleton<int,
{
};

[I didn't compile any of this, please take it as a hint only, not as
real code]

Victor


Thanks for the quick reply, Victor! A bit more advanced than my attempt,
an attempt that ended in me noticing that a function can't be both
static and virtual. =(
I don't fully understand yet how I should use your design with my rather
complex classes. But I want to understand so I can use it!

/ WP

Hmm, I don't understand...doesn't one need some sort of base
ConstructionPolicy-class from which one derives? But if one has such a
class, one is confronted with the problem that a member function cannot
be both virtual and static. This code doesn't compile and that's because
the compiler sees a ValueConstructionPolicy when it wants a class named
ConstructionPolicy, right?

template <typename T>
class DefaultConstructionPolicy
{
public:
static T* create()
{
return new T;
}
};

template <typename T, T t_def>
class ValueConstructionPolicy
{
public:
static T* create()
{
return new T(t_def);
}
};

template <typename T, template <class> class ConstructionPolicy>
class Singleton
{
public:
static T* get_instance()
{
if(!t)
{
t = ConstructionPolicy<T>::create();
}

return t;
}

private:
Singleton()
{
; /* Never reached. */
}

static T* t;
};

class int_singleton : public Singleton<int, ValueConstructionPolicy<int,
4711> >
{
};

template <typename T>
T* Singleton<T, ConstructionPolicy>::t = NULL;

The compiler says:
singleton.hpp:60: error: type/value mismatch at argument 2 in template
parameter list for `template<class T, template<class> class
ConstructionPolicy> class Singleton'
singleton.hpp:60: error: expected a class template, got
`ValueConstructionPolicy<int, 4711>'
singleton.hpp:72: error: `ConstructionPolicy' was not declared in this scope
singleton.hpp:72: error: template argument 2 is invalid
singleton.hpp:72: error: template declaration of `T*t'

Line 60 is the opening { of the int_singleton class.
Line 72 is the definition of the static data member.

How should I solve this?

/ WP
 
V

Victor Bazarov

William Payne said:
[...]
Hmm, I don't understand...doesn't one need some sort of base
ConstructionPolicy-class from which one derives? But if one has such a
class, one is confronted with the problem that a member function cannot be
both virtual and static. This code doesn't compile and that's because the
compiler sees a ValueConstructionPolicy when it wants a class named
ConstructionPolicy, right?

Right. I thought a bit about it after I posted. Yes, I am still going
to hide behind the disclaimer: what I posted was for illustration only.
To make it work, you still need to research policy-based design and do
a bit of creative thinking. Get a copy of "Modern C++ Design" by Andrei
Alexandrescu.
 
W

William Payne

Victor said:
William Payne said:
[...]
Hmm, I don't understand...doesn't one need some sort of base
ConstructionPolicy-class from which one derives? But if one has such a
class, one is confronted with the problem that a member function cannot be
both virtual and static. This code doesn't compile and that's because the
compiler sees a ValueConstructionPolicy when it wants a class named
ConstructionPolicy, right?


Right. I thought a bit about it after I posted. Yes, I am still going
to hide behind the disclaimer: what I posted was for illustration only.
To make it work, you still need to research policy-based design and do
a bit of creative thinking. Get a copy of "Modern C++ Design" by Andrei
Alexandrescu.

I don't see a way around the static-but-not-virtual-or-vice-versa-issue,
but maybe I can use a pointer to a (templated) function as the
construction policy? Ideas welcome!
I will check out the book when I go downtown friday, thanks!

/ WP
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top