template const trick versus myers singleton - global data revisited

M

ma740988

I was perusing a thread a while back where the OP was trying to
determine how to express global data without polluting every
translation unit (TU) with global data a TU may not care about. There
was discussion about the use of a 'template constant trick' (I suspect
there's another name for this because I've come up short during a
seach of my texts and google) or a myers singleton. So now
consider:

# include <limits>
# include <iostream>

///form a
template < typename dummy >
struct consts // constants
{
//static int const MAX_INT = std::numeric_limits < int >::max
() ; //Visual studio 9 complains... check standard, i think this is
legal
static int const MAX_INT = INT_MAX ;
static double const PI ;
};

typedef consts<void> constants;
double const constants::pI = 3.14159;

///form b
class c_constants {
public :
double const PI ;
static int const MAX_INT = INT_MAX ;
c_constants()
: PI ( 3.14159 )
{}
static c_constants& instance() {
static c_constants inst ;
return inst ;
}
};

int main()
{

std::cout << constants::pI << '\n';
std::cout << c_constants::instance().PI << '\n';
std::cin.get();

}

It seems to me that the prime difference between the two foms (a) and
(b) is that with (a) I'm unable to express PI without the static
keyword. True/False?

One other thing: There was discussion about static initialization
fiasco so consider:

class foo {
static int const MAGIC = 0xBEEF ;
public :
static foo& instance () { static foo inst; return inst; }
void do_work()
{ int const whatever = c_constants::instance().MAX_INT -
MAGIC; }
} ;

Here a foo object could potentially be created/initialized before
c_constant object which is used in the do_work method. Would the
static initialization fiasco matter here?
 
A

Alf P. Steinbach

* ma740988:
I was perusing a thread a while back where the OP was trying to
determine how to express global data without polluting every
translation unit (TU) with global data a TU may not care about. There
was discussion about the use of a 'template constant trick' (I suspect
there's another name for this because I've come up short during a
seach of my texts and google) or a myers singleton. So now
consider:

# include <limits>
# include <iostream>

///form a
template < typename dummy >
struct consts // constants
{
//static int const MAX_INT = std::numeric_limits < int >::max
() ; //Visual studio 9 complains... check standard, i think this is
legal
static int const MAX_INT = INT_MAX ;
static double const PI ;

Try to avoid using all uppercase names, except for macros which should have such
names. This helps reduce the chance of undesired text replacement.

};

typedef consts<void> constants;
double const constants::pI = 3.14159;

In a single file program this will work, but if you do it in a header file,
which is the main point of the templated const trick, then you risk multiple
definitions, that is, running afoul of the One Definition Rule.

Instead do

template< typename Dummy >
double const consts<Dummy>::pI = 3.14159;

There is a special exemption for this, or put another way, the ODR allows this,
in order to make it possible to define templates in header files.

///form b
class c_constants {
public :
double const PI ;
static int const MAX_INT = INT_MAX ;
c_constants()
: PI ( 3.14159 )
{}
static c_constants& instance() {
static c_constants inst ;
return inst ;
}
};

int main()
{

std::cout << constants::pI << '\n';
std::cout << c_constants::instance().PI << '\n';
std::cin.get();

}

It seems to me that the prime difference between the two foms (a) and
(b) is that with (a) I'm unable to express PI without the static
keyword. True/False?

Not sure what you mean about "static keyword" but the templated const allows you
to define constants in a header file and for each such constant have only one
occurrence of the value in the final program, without relying on optimizations.

One other thing: There was discussion about static initialization
fiasco so consider:

class foo {
static int const MAGIC = 0xBEEF ;
public :
static foo& instance () { static foo inst; return inst; }
void do_work()
{ int const whatever = c_constants::instance().MAX_INT -
MAGIC; }
} ;

Here a foo object could potentially be created/initialized before
c_constant object which is used in the do_work method. Would the
static initialization fiasco matter here?

Not for this concrete example, because the static initialization fiasco is about
dynamic initialization, initialization that involves execution of user code, and
your constants are of built-in type:

First, static initialization is performed, which consists of, in order,
zero-initialization, and then
initialization with constant expressions (compile time constants),
then
dynamic initialization.

And the problem is that C++ does not strictly define the order that different
compilation units' dynamic initialization is performed in.

So with e.g. std::string constants the templated const trick in general runs the
risk of a static initialization order fiasco, since it just defines an ordinary
namespace scope constant, which might be accessed (from some other compilation
unit's dynamic initialization) before its constructor runs.

One way to avoid that is to wrap the constant in a function:

inline std::string const& piChars()
{
std::string const theValue = "3.141592654";
return theValue;
}

instead of

std::string const piChars = "3.141592654";


Cheers & hth.,

- Alf
 
T

Technical

In a single file program this will work, but if you do it in a header file,
which is the main point of the templated const trick, then you risk multiple
definitions, that is, running afoul of the One Definition Rule.

Instead do

   template< typename Dummy >
   double const consts<Dummy>::pI = 3.14159;

There is a special exemption for this, or put another way, the ODR allows this,
in order to make it possible to define templates in header files.

Is there another name for the 'templated const trick'? With regards
to the ODR (this is where I get confused at times), why wouldn't i run
the risk of violation if I do:
// header.h
#ifndef HEADER
#define HEADER
static const double PI = 3.14159;
#endif

// foo.cpp - assume there's a foo.h
# include "header.h"
foo::foo()
{ std::cout << PI << '\n' }

// bar.cpp - assume there's a bar.h
# include "header.h"
bar::bar()
{ std::cout << PI << '\n' }


Not sure what you mean about "static keyword" but the templated const allows you
to define constants in a header file and for each such constant have only one
occurrence of the value in the final program, without relying on optimizations.
Well I was referring to 'form b'. The c_constants class. The one
advantage I see with the singleton approach is static keyword is not
required on for the variable PI and PI can be initialized using the
constructor. That's perhaps the only drawback I see with the
templated const trick. I can't use a constructor to initialize PI
while achieving the objective.

Not for this concrete example, because the static initialization fiasco is about
dynamic initialization, initialization that involves execution of user code, and
your constants are of built-in type:

   First, static initialization is performed, which consists of, in order,
      zero-initialization, and then
      initialization with constant expressions (compile time constants),
   then
      dynamic initialization.

And the problem is that C++ does not strictly define the order that different
compilation units' dynamic initialization is performed in.

So with e.g. std::string constants the templated const trick in general runs the
risk of a static initialization order fiasco, since it just defines an ordinary
namespace scope constant, which might be accessed (from some other compilation
unit's dynamic initialization) before its constructor runs.

One way to avoid that is to wrap the constant in a function:

   inline std::string const& piChars()
   {
       std::string const theValue = "3.141592654";
       return theValue;
   }

That should really be:
inline static std::string const& piChars()
{ static std::string const theValue = "3.141592654"; return
theValue; }
Correct?
instead of
std::string const piChars = "3.141592654";

Of course only static ocnst integral types can be defined within the
composite type 'consts' but given the context point taken
 
A

Alf P. Steinbach

* Technical:
Is there another name for the 'templated const trick'?

Not as far as I know, except replacing 'trick' with 'idiom' or 'technique'.

And as far as I know using a class template solely in order to define (and
possibly inherit) constants in header files is my invention, first and only time
used for helping define 'char' and 'wchar_t' versions of the same string
constants, and if so, then I get to name it. ;-)

But then, every thing I've ever thought I'd invented has turned out to to have
been invented by at least 1 person prior to myself, and I don't discount the
possibility that I've simply seen it somewhere, e.g. in a newsgroup posting.

With regards
to the ODR (this is where I get confused at times), why wouldn't i run
the risk of violation if I do:
// header.h
#ifndef HEADER
#define HEADER
static const double PI = 3.14159;
#endif

Because here PI has internal linkage, which means that (when disregarding
optimization) there's one copy of it in every compilation unit where it's used,
each compilation unit using its own copy -- instead of multiple definitions of
a common single program-wide instance.

Internal linkage is the default for a const at namespace scope.

And so above the keyword 'static' is redundant -- unlike my typo below...

Well I was referring to 'form b'. The c_constants class. The one
advantage I see with the singleton approach is static keyword is not
required on for the variable PI and PI can be initialized using the
constructor. That's perhaps the only drawback I see with the
templated const trick. I can't use a constructor to initialize PI
while achieving the objective.

I'm still not sure exactly what you mean.

That should really be:
inline static std::string const& piChars()
{ static std::string const theValue = "3.141592654"; return
theValue; }
Correct?

Yes regarding the second 'static' you added here, and sorry; I meant to write

inline std::string const& piChars()
{
static std::string const theValue = "3.141592654";
return theValue;
}

The first 'static' you added, however, would make this function have internal
linkage, and so would (modulo optimization) place a copy of both the function
and its wrapped constant in every compilation unit where it's used.

The 'inline' is to allow multiple definitions of the function (one per
compilation unit, only one of them being picked for the final program).

Of course only static ocnst integral types can be defined within the
composite type 'consts' but given the context point taken

Depends what you mean. The templated const trick is mostly for where you need a
/non-integral/ type constant. That is, except for possible static initialization
fiasco issues you can safely do this, in a header file:

template< typename Dummy >
struct Names_ { static std::string const cppLanguageCreator; };

template< typename Dummy >
std::string const Names_<Dummy>::cppLanguageCreator = "Bjarne Stroustrup";

typedef Names_<void> Names;


Cheers & hth.,

- Alf
 
T

Technical

Internal linkage is the default for a const at namespace scope.

And so above the keyword 'static' is redundant  --  unlike my typo below...
Correct! I tend to forget the 'redundancy' from time to time, you'd
think by now I'd learn.
I'm still not sure exactly what you mean.

Givent the two forms: form (a)and form (b)
///form a
template < typename dummy >
struct consts // constants
{ static double const PI; };
template< typename dummy > double const consts<dummy>::pI =
3.14159;
typedef consts<void> constants;

///form b
class c_constants {
public :
double const PI ;
static int const MAX_INT = INT_MAX ;
c_constants()
: PI ( 3.14159 )
{}
static c_constants& instance() {
static c_constants inst ;
return inst ;
}
};

With the Myers singleton PI is declared as 'double const PI' and is
initialized in the constructor. With the templated const trick PI is/
must be declared as 'static double const PI' and is defined outside of
the struct i.e. template< typename dummy > double const
consts<dummy>::pI = 3.14159;. Just trying to summarize the difference
(initialization list with Myers end elimination of the 'static'
keyword, versus using the static keyword and providing the definition
outside of the strut) in my mind and more importantly see if theres
any advantage.

The first 'static' you added, however, would make this function have internal
linkage, and so would (modulo optimization) place a copy of both the function
and its wrapped constant in every compilation unit where it's used.

Interesting, this is also true for the 'form b'. i.e
static c_constants& instance() {
static c_constants inst ;
return inst ;
}

instance has internal linkage and would place a copy of the function
and it's wrapped contents in every complilation unit where its used.
The 'inline' is to allow multiple definitions of the function (one per
compilation unit, only one of them being picked for the final program).
Got it! Learned something new today.
 
A

Alf P. Steinbach

* Technical:
Correct! I tend to forget the 'redundancy' from time to time, you'd
think by now I'd learn.


Givent the two forms: form (a)and form (b)
///form a
template < typename dummy >
struct consts // constants
{ static double const PI; };
template< typename dummy > double const consts<dummy>::pI =
3.14159;
typedef consts<void> constants;

///form b
class c_constants {
public :
double const PI ;
static int const MAX_INT = INT_MAX ;
c_constants()
: PI ( 3.14159 )
{}
static c_constants& instance() {
static c_constants inst ;
return inst ;
}
};

With the Myers singleton PI is declared as 'double const PI' and is
initialized in the constructor. With the templated const trick PI is/
must be declared as 'static double const PI' and is defined outside of
the struct i.e. template< typename dummy > double const
consts<dummy>::pI = 3.14159;. Just trying to summarize the difference
(initialization list with Myers end elimination of the 'static'
keyword, versus using the static keyword and providing the definition
outside of the strut) in my mind and more importantly see if theres
any advantage.

OK.

There are notational and efficiency differences. Functionally the main
difference is that the templated const can provide a compile time constant, e.g.
one that can be used to dimension a raw array type, but (for other usage) the
templated const is subject to possible static initialization order fiasco.

Interesting, this is also true for the 'form b'. i.e
static c_constants& instance() {
static c_constants inst ;
return inst ;
}

No, for a class member declaration the keyword 'static' does not imply internal
linkage.

instance has internal linkage and would place a copy of the function
and it's wrapped contents in every complilation unit where its used.

Got it! Learned something new today.

:)


Cheers & hth.,

- Alf
 
T

Technical

Depends what you mean. The templated const trick is mostly for where you need a
/non-integral/ type constant. That is, except for possible static initialization
fiasco issues you can safely do this, in a header file:

   template< typename Dummy >
   struct Names_ { static std::string const cppLanguageCreator; };

   template< typename Dummy >
   std::string const Names_<Dummy>::cppLanguageCreator = "Bjarne Stroustrup";

   typedef Names_<void> Names;

It's slowly coming together for me. Last(hopefully) quesiton.
Consider

template < typename dummy >
struct consts // constants
{
static double const PI;
inline static std::string const& creator()
{
static std::string const cppLanguageCreator = "Bjarne
Stroustrup";
return ( cppLanguageCreator );
}

};
template< typename dummy > double const consts<dummy>::pI =
3.14159;
typedef consts<void> constants;

Would the creator method within the struct be a a suitable alternative
to circumventing the possible static initialization fiasco?
 
A

Alf P. Steinbach

* Technical:
It's slowly coming together for me. Last(hopefully) quesiton.
Consider

template < typename dummy >
struct consts // constants
{
static double const PI;
inline static std::string const& creator()
{
static std::string const cppLanguageCreator = "Bjarne
Stroustrup";
return ( cppLanguageCreator );
}

};
template< typename dummy > double const consts<dummy>::pI =
3.14159;
typedef consts<void> constants;

Would the creator method within the struct be a a suitable alternative
to circumventing the possible static initialization fiasco?

Yes.

But on the other hand, the member routine gives more verbose and less readable
notation, possible nano-second-inefficiency (I'm mentioning that just for
completeness), and it can't deliver a compile time constant, that is, one that
can be used in declarations requiring compile time constant.

The main utility of the templated const trick has so far been in /debates/ about
allowing definitions of constants of any type for which a constant can be
defined, within a class definition, because via the templated const trick any
such in-class constant definition can be mechanically rewritten to standard
C++98, demonstrating that there's no particular technical show-stopper and that
current compilers already implement the basic machinery to handle them. I'm not
familiar enough with C++0x to say whether it's got those constants. But my
impression is that it has, that is, that C++0x will support such syntax (if you
want to check: the draft is available from the committe pages in PDF format).


Cheers & hth.,

- Alf

PS: a member routine defined in the class definition is implicitly 'inline', so
that keyword is superfluous in the example above.
 

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,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top