forward-decl for Singleton?

M

Markus Dehmann

I need a Singleton for general program options so that all classes can
access it.

I use the code below (adapted from the Wikipedia singleton example).
But the problem is if I change one variable in it, all my classes have
to re-compile. But I am planning to add more options often during
development. I tried to solve it through a forward declaration "class
Opts;", but didn't succeed because Opts::instance() results in an
error message about the incomplete type.

One solution might be to use a key-value map, but I would prefer to
use the variables directly, because they can be accessed faster, and
all possible options are known at compile-time.

Does anyone have a hint how to do the forward decl so that I don't
have to recompile every class that includes the Opts decl whenever I
add an option?

Thanks!
Markus

// header singleton.h
template<typename T> class Singleton{
public:
static T& Instance(){
static T theSingleInstance; // assumes T has a protected
default constructor
return theSingleInstance;
}
};

// header opts.h
class Opts : public Singleton<Opts>{
friend class Singleton<Opts>;
public:
int option1;
bool option2;
protected:
Opts(): option1(42), option2(false); // defaults
};

// opts.cc
Opts::Opts() {}
 
W

werasm

I need a Singleton for general program options so that all classes can
access it.

I use the code below (adapted from the Wikipedia singleton example).
But the problem is if I change one variable in it, all my classes have
to re-compile. But I am planning to add more options often during
development. I tried to solve it through a forward declaration "class
Opts;", but didn't succeed because Opts::instance() results in an
error message about the incomplete type.

One solution might be to use a key-value map, but I would prefer to
use the variables directly, because they can be accessed faster, and
all possible options are known at compile-time.

Does anyone have a hint how to do the forward decl so that I don't
have to recompile every class that includes the Opts decl whenever I
add an option?

Thanks!
Markus

// header singleton.h
template<typename T> class Singleton{
public:
static T& Instance(){
static T theSingleInstance; // assumes T has a protected
default constructor


I've written a little test to see if this works (especially this
assumption stated here above about protected default:

template <class T>
struct Base
{
static T& instance()
{
static T failToCompile;
return failToCompile;
}
};

struct Derived
{
protected:
Derived(){}
};

int main()
{
Derived& d = Base<Derived>::instance();
return 0;
}

Looks like it does not like the base attempting to call
the protected constructor in the derived. ;-)

Regards,

Werner
 
W

werasm

Does anyone have a hint how to do the forward decl so that I don't
have to recompile every class that includes the Opts decl whenever I
add an option?

Someone may have a solution, but I would try to give the generic base
a clear responsibility - singleton instantiation of the applicable
derived. If options are applicable to the derived only, then it should
not be part of the singleton. I suppose the reason you want to make
it part of the singleton is because you need to instantiate each
derived with options. A couple of questions then come to mind.

- Is the type of the options unique per singleton/derived?
- If not unique, can the type of options vary.
- Can the value of options vary (is it default constructible or does
is only have static const members.

An idea might be to let the derived get its options from
a factory during its construction possible using typeid
or a string. I personally don't think it is idiomatic to
have arguments in instance. Otherwise you could possible
consider explicit creation of the singleton which
uses a non-instance method, the creation taking option
as argument.

In general the implementation of template code should be
stable as modification to it affects all translation units
that use it. If this is not the case, I think the unstable
code should be moved.

Hope this helps a little.

Regards,

Werner
 
M

Markus Dehmann

Someone may have a solution, but I would try to give the generic base
a clear responsibility - singleton instantiation of the applicable
derived. If options are applicable to the derived only, then it should
not be part of the singleton. I suppose the reason you want to make
it part of the singleton is because you need to instantiate each
derived with options. A couple of questions then come to mind.

I think there is a misunderstanding. All I care about is that I can
use the Opts class anywhere (globally) in my code, using calls like
this:

// set a global value
Opts::Instance().option1 = 124;
// get a global value
if(Opts::Instance().option2){
// do something
}

That's the typical use for the singleton design pattern. I happened to
give code that implements a special Singleton class providing the
Instance() method, but I could have implemented this function directly
in the Opts class and not use inheritance.

The question is how to make calls like "Opts::Instance().option1"
possible, but with a design that allows for a forward declaration of
the class Opts, so that I can add or remove variables in the class
(like int option1, or bool option2) without having to recompile my
whole project (because many files will want to include the Opts
class.)
- Is the type of the options unique per singleton/derived?
- If not unique, can the type of options vary.
- Can the value of options vary (is it default constructible or does
is only have static const members.

The values can vary. Any caller may set or get the public variables.
(I don't think getter and setter methods are necessary.)
An idea might be to let the derived get its options from
a factory during its construction possible using typeid
or a string. I personally don't think it is idiomatic to
have arguments in instance. Otherwise you could possible
consider explicit creation of the singleton which
uses a non-instance method, the creation taking option
as argument.

Using a factory might be an idea ...
In general the implementation of template code should be
stable as modification to it affects all translation units
that use it. If this is not the case, I think the unstable
code should be moved.

Yes, I don't expect the Singleton class to be modified during
development. Just the Opts class, whenever we add another option
variable (e.g. double option3;)

--Markus
 
A

anon

Markus said:
I use the code below (adapted from the Wikipedia singleton example).
But the problem is if I change one variable in it, all my classes have
to re-compile. But I am planning to add more options often during
development. I tried to solve it through a forward declaration "class
Opts;", but didn't succeed because Opts::instance() results in an
error message about the incomplete type.

[snip]


// header singleton.h
template<typename T> class Singleton{
public:
static T& Instance(){
static T theSingleInstance; // assumes T has a protected
default constructor
return theSingleInstance;
}
};

// header opts.h
class Opts : public Singleton<Opts>{
friend class Singleton<Opts>;
public:
int option1;
bool option2;
protected:
Opts(): option1(42), option2(false); // defaults
};

// opts.cc
Opts::Opts() {}

Search for the pImpl idiom.

It should look something like this:

// header opts.h
class Opts : public Singleton<Opts>{
friend class Singleton<Opts>;
public:
class Impl;
std::auto_ptr< Impl > pImpl;
protected:
Opts(): option1(42), option2(false); // defaults
};

// opts.cc
class Opts::Impl
{
public:
Impl() {}
~Impl(){}

// add options here
}

Opts::Opts() : pImpl( new Impl )
{
}

Adding options, your interface for the class Opts does not change to
outside world, and you can easily add more options.
 
B

Bart van Ingen Schenau

I need a Singleton for general program options so that all classes can
access it.

I use the code below (adapted from the Wikipedia singleton example).
But the problem is if I change one variable in it, all my classes have
to re-compile. But I am planning to add more options often during
development. I tried to solve it through a forward declaration "class
Opts;", but didn't succeed because Opts::instance() results in an
error message about the incomplete type.

One solution might be to use a key-value map, but I would prefer to
use the variables directly, because they can be accessed faster, and
all possible options are known at compile-time.

Does anyone have a hint how to do the forward decl so that I don't
have to recompile every class that includes the Opts decl whenever I
add an option?

The problem is that a forward declaration will not cut it. The
compiler will never take your word for it that Opts has a particular
member unless it has seen the definition of Opts.

If you really want to access the options as members of the Opts class,
then there is no way to avoid the recompilation of all dependent code
when you add a new option variable/function.
The reason is that the build system only sees that a particular file
has changed, without knowing what kind of changes were made. To be on
the safe side, the build system assumes that an interface change has
been made that affects all dependent code, so that all has to be
rebuilt.

Thanks!
Markus
Bart v Ingen Schenau
 

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
474,181
Messages
2,570,970
Members
47,537
Latest member
BellCorone

Latest Threads

Top