question on c++ constants?

I

Ioannis Vranos

shuisheng said:
Dear All,

I am always confused in using constants in multiple files.

For global constants, I got some clues from
http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx

So in header file writing: const double PI = 3.14;
Every time using it, include the header file.

But how about constants in namespaces and classes?

Thanks for your help!

Shuisheng



1. The easiest constants in classes are made by using enums:


#include <vector>

class SomeClass
{
enum { SIZE= 7 };

int array[SIZE];

std::vector<int> intVector;


public:
SomeClass(): intVector(5) {}
};



2. Regarding global constants and the header file you mentioned, in
simple words:

You can #include the header file with the global constant only in one
"implementation" file (e.g. .cpp) and to the rest implementation files
(e.g. .cpp), you can add the declaration:


extern const double PI;


==> In general avoid objects in the global namespace.





3. Regarding constants in namespaces, you have to include the definition
in the implementation file (e.g. by placing it in the header file).
file1.cpp:


E.g. pi.h:

namespace SomeNamespace
{
const double PI = 3.14;
}




What should be preferred instead of constants in the global namespace:

Constants (consts/enums) in anonymous namespaces (= local file scope
only), and constants (consts/enums) in named namespaces.


Regarding classes, you can either use static constants or (usually
better) enums.
 
I

Ioannis Vranos

Corrected:


Dear All,

I am always confused in using constants in multiple files.

For global constants, I got some clues from
http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx

So in header file writing: const double PI = 3.14;
Every time using it, include the header file.

But how about constants in namespaces and classes?

Thanks for your help!

Shuisheng


1. The easiest constants in classes are made by using enums:


#include <vector>

class SomeClass
{
enum { SIZE= 7 };

int array[SIZE];

std::vector<int> intVector;


public:
SomeClass(): intVector(SIZE) {}
};



2. Regarding global constants and the header file you mentioned, in
simple words:

You can #include the header file with the global constant only in one
"implementation" file (e.g. .cpp) and to the rest implementation files
(e.g. .cpp), you can add the declaration:


extern const double PI;


==> In general avoid objects in the global namespace.





3. Regarding constants in namespaces, you have to include the definition
in the implementation file (e.g. by placing it in the header file).
file1.cpp:


E.g. pi.h:

namespace SomeNamespace
{
const double PI = 3.14;
}




What should be preferred instead of constants in the global namespace:

Constants (consts/enums) in anonymous namespaces (= local file scope
only), and constants (consts/enums) in named namespaces.


Regarding classes, you can either use static constants or (usually
better) enums.
 
S

shuisheng

Ioannis said:
Corrected:
[..]
Regarding classes, you can either use static constants or (usually
better) enums.

Well, there aren't double or string enums, so...  The difference between
the class [non-integral] constants and the namespace ones is that the
class constants have to be declared in the class and *defined* in some
translation unit, while the namespace constants can be defined in the
header (which means they will be duplicated in every translation unit
that includes the header), which is OK because they have internal
linkage (unless you specify otherwise).

V

So I think the following is the right way, please confirm it. I use PI
as an example.

For global constants:

// in constants.h
const double PI = 3.14;

// in h or cpp files to use PI
#include "constants.h"
double a = PI;


For constants in namespace:

// in constants.h
namespace constants
{
const double PI = 3.14;
};

// in h or cpp files to use PI
#include "constants.h"
double d = constants::pI;


For constants in classes:

// in class.h
class A
{
public:
static const double PI;
};

// in class.cpp
const double A::pI = 3.14;

// in h and cpp files to use it.
#include "class.h"
double a = A::pI;

And I think Ioannis Vranos's way to define global constants will bring
about problems as shown in http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx

Thanks and best regards,
 
S

shuisheng

shuisheng said:
[..]
So I think the following is the right way, please confirm it. I use PI
as an example.
For global constants:
  // in constants.h
  const double PI = 3.14;
  // in h or cpp files to use PI
  #include "constants.h"
  double a = PI;
For constants in namespace:
  // in constants.h
  namespace constants
  {
    const double PI = 3.14;
  };
  // in h or cpp files to use PI
  #include "constants.h"
  double d = constants::pI;
For constants in classes:
  // in class.h
  class A
  {
  public:
    static const double PI;
  };
  // in class.cpp
  const double A::pI = 3.14;
  // in h and cpp files to use it.
  #include "class.h"
  double a = A::pI;
And I think Ioannis Vranos's way to define global constants will bring
about problems as shown inhttp://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx

The code you showed here is perfectly fine, and you can declare/define
any constants that way, not just of fundamental types, AFAIC.

The contents of the web page you cited do bother me.  I am not sure what
"static linkage" is; there is no such term in C++ Standard.  Why would
the page say that "If you try to use a global constant in C++ in
multiple files you get an unresolved external error"?  What kind of
nonsense is that?  If you *do* declare some object "extern", then you
must define it somewhere.  If you don't defined it, you violate the ODR..

The point in using constants like you've shown is that there *is* a
*defined* object in every module, it has internal linkage (since it's
declared 'const' and does not have external linkage), and that's it.
Whether those objects are "optimized out" does not matter.  From the
language point of view they exist, have value, are constant, and that's
about all we need to know.

V

I tested using "extern" as following in visual studio 2005.

//! in constants.h
extern const double PI;

//! in constants.cpp
const double PI = 3.14;

When using for multiple files, especially when PI is defined in a
library, it gives a link error. I think C++ treats global constants
different from global non-constant variables. My understanding is
that: there is no external objects somewhere for global constants,
even in "constants.cpp" having the code "const double PI = 3.14;".
 
I

Ioannis Vranos

shuisheng said:
So I think the following is the right way, please confirm it. I use PI
as an example.

For global constants:

// in constants.h
const double PI = 3.14;

// in h or cpp files to use PI
#include "constants.h"
double a = PI;


This is OK, but try not polluting the global namespace.


For constants in namespace:

// in constants.h
namespace constants
{
const double PI = 3.14;
};

// in h or cpp files to use PI
#include "constants.h"
double d = constants::pI;


There are also the anonymous namespaces which have local file scope:


namespace
{
const double PI= 3.14;
};


For constants in classes:

// in class.h
class A
{
public:
static const double PI;
};

// in class.cpp
const double A::pI = 3.14;

// in h and cpp files to use it.
#include "class.h"
double a = A::pI;


or enums for integer constants.


And I think Ioannis Vranos's way to define global constants will bring
about problems as shown in http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx


Yes you are right. This is one of the differences between C++ and C.

Victor check TC++PL3 on page 200.


const int x= 7; in global scope is equivalent to

static const int x= 7;


For this to work as C, definition must be accompanied with the word
extern, that is:


extern const double PI= 3.14;


But as I said, we must avoid global variables as much as possible and
must avoid polluting the global namespace as much as possible.
 
I

Ioannis Vranos

Recorrected:

Dear All,

I am always confused in using constants in multiple files.

For global constants, I got some clues from
http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx

So in header file writing: const double PI = 3.14;
Every time using it, include the header file.

But how about constants in namespaces and classes?

Thanks for your help!

Shuisheng


Corrected:


> Dear All,
>
> I am always confused in using constants in multiple files.
>
> For global constants, I got some clues from
> http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx
>
> So in header file writing: const double PI = 3.14;
> Every time using it, include the header file.
>
> But how about constants in namespaces and classes?
>
> Thanks for your help!
>
> Shuisheng


1. The easiest constants in classes are made by using enums:


#include <vector>

class SomeClass
{
enum { SIZE= 7 };

int array[SIZE];

std::vector<int> intVector;


public:
SomeClass(): intVector(SIZE) {}
};



2. Regarding global constants and the header file you mentioned, in
simple words:

i) You can #include the header file (e.g .h) in all implementation files
(e.g. .cpp), keeping in mind that as a result, each instance of the
constant (defined as const double PI= 3.14;) is a different file-scope
(more accurately, compilation unit - scope) object.


ii) You can #include the header file with the global constant in the form:


extern const double PI= 3.14;


in one "implementation" file (e.g. .cpp) and to the rest implementation
files (e.g. .cpp), you can add the declaration:


extern const double PI;




==> In general avoid objects in the global namespace.



3. Regarding constants in namespaces, you have to include the definition
in the implementation file (e.g. by placing it in the header file).


E.g. pi.h:

namespace SomeNamespace
{
const double PI = 3.14;
}




What should be preferred instead of constants in the global namespace:

Constants (consts/enums) in anonymous namespaces (= local file scope
only), and constants (consts/enums) in named namespaces.


Regarding classes, you can either use static constants or (usually
better) enums.
 
J

James Kanze

1. The easiest constants in classes are made by using enums:
#include <vector>
class SomeClass
{
     enum { SIZE= 7 };
     int array[SIZE];
     std::vector<int> intVector;
     public:
         SomeClass(): intVector(SIZE) {}
};

Two problems with this. The first is that it can only be used
for integral constants; it doesn't work for floating point (the
actual example) or user defined types. The second is that even
for integral constants, the type is wrong, which has
repercusions with regards to function overload resolution and
templates.

The usual solution here is to declare a static const member,
e.g.:

class SomeClass
{
public:
static std::size_t const size = 7 ;
static double const pi ;
// ...
} ;

In all cases, you must define the variable in a single source
file. In the case of an integral constant, you can put the
initializer (the value) either in the declaration in the class,
or in the definition. For all other types, the initializer can
only go in the definition.
2. Regarding global constants and the header file you mentioned, in
simple words:
You can #include the header file with the global constant only in one
"implementation" file (e.g. .cpp) and to the rest implementation files
(e.g. .cpp), you can add the declaration:
extern const double PI;

In that case, you must also declare the definition extern:

extern double const PI = 3.14 ;

Otherwise, it doesn't have external linkage.

It's more frequent to simply write:

double const PI = 3.14 ;

in the header. Be aware, however, that this means that &PI may
not always be the same thing. (Not usually a problem for the
standard arithmetic types, but it easily could be a problem with
user defined types.)
==> In general avoid objects in the global namespace.

Except maybe for some global constants:).
3. Regarding constants in namespaces, you have to include the definition
in the implementation file (e.g.  by placing it in the header file).
file1.cpp:
E.g. pi.h:

namespace SomeNamespace
{
     const double PI = 3.14;
}
What should be preferred instead of constants in the global
namespace:
Constants (consts/enums) in anonymous namespaces (= local file
scope only), and constants (consts/enums) in named namespaces.

I don't think that that's a good general policy. You don't want
to have an anonymous namespace in a header, since it's generally
a very good way to end up with undefined behavior.
Regarding classes, you can either use static constants or
(usually better) enums.

Enums were what was used before the rules were changed to allow
the initializer in the declaration. The rule was changed
because using enums created too many problems due to the type
being wrong.
 
I

Ioannis Vranos

James said:
1. The easiest constants in classes are made by using enums:
#include <vector>
class SomeClass
{
enum { SIZE= 7 };
int array[SIZE];
std::vector<int> intVector;
public:
SomeClass(): intVector(SIZE) {}
};

Two problems with this. The first is that it can only be used
for integral constants; it doesn't work for floating point (the
actual example) or user defined types.


Yes, my notion was "where applicable".

The second is that even
for integral constants, the type is wrong, which has
repercusions with regards to function overload resolution and
templates.


What you mean "the type is wrong"? If I defined it as a


static const short SIZE;

inside the function declaration, would the type be right?

I don't think that that's a good general policy. You don't want
to have an anonymous namespace in a header, since it's generally
a very good way to end up with undefined behavior.


Speaking about local file scope (or better compilation unit - scope), I
implied the anonymous namespaces are to be used in .cpp files.
 
I

Ioannis Vranos

James said:
>
>> 1. The easiest constants in classes are made by using enums:
>
>> #include <vector>
>
>> class SomeClass
>> {
>> enum { SIZE= 7 };
>
>> int array[SIZE];
>
>> std::vector<int> intVector;
>
>> public:
>> SomeClass(): intVector(SIZE) {}
>> };
>
> Two problems with this. The first is that it can only be used
> for integral constants; it doesn't work for floating point (the
> actual example) or user defined types.


Yes, my notion was "where applicable".

> The second is that even
> for integral constants, the type is wrong, which has
> repercusions with regards to function overload resolution and
> templates.


What you mean "the type is wrong"? If I defined it as a


static const short SIZE;

inside the class declaration, would the type be right?

> I don't think that that's a good general policy. You don't want
> to have an anonymous namespace in a header, since it's generally
> a very good way to end up with undefined behavior.


Speaking about local file scope (or better compilation unit - scope), I
implied the anonymous namespaces are to be used in .cpp files.
 
I

Ioannis Vranos

Victor said:
Ioannis said:
[..]
Speaking about local file scope (or better compilation unit - scope),
I implied the anonymous namespaces are to be used in .cpp files.

What would be the difference for a constant (or its use) if it's defined
inside the anonymous namespace versus if it's defined in the global
namespace? Unless somebody else introduces the declaration of the same
constant with external linkage in some header included in this TU
previously to the definition of the constant, what is there to worry
about? Why the anonymous namespace?


In a facilities (library) notion, we must always try not polluting the
global namespace.


An example: Using the "using namespace std;" statement in global scope,
is an attempt to defeat the namespace system.

Namespaces exist to isolate our code in modules.


In general, it is good to create our program as a library.
 
I

Ioannis Vranos

Ioannis said:
In a facilities (library) notion, we must always try not polluting the
global namespace.


An example: Using the "using namespace std;" statement in global scope,
is an attempt to defeat the namespace system.

Namespaces exist to isolate our code in modules.


In general, it is good to create our program as a library.


In the case of global non-extern consts, the effect is the same as if
they are defined in an anonymous namespace, but it is easier to place
everything in a suitable namespace, rather than thinking such subtle
details.
 
I

Ioannis Vranos

Ioannis said:
>
> In a facilities (library) notion, we must always try not polluting the global namespace.
>
>
> An example: Using the "using namespace std;" statement in global
scope, is an attempt to defeat the namespace system.
>
> Namespaces exist to isolate our code in modules.
>
>
> In general, it is good to create our program as a library.


In the case of global non-extern consts, the effect is the same as if
they are defined in an anonymous namespace, but it is easier to place
everything in a suitable namespace, rather than thinking such subtle
details.
 
J

James Kanze

"Suitable namespace"? "Thinking such subtle details"? If
"the effect is the same", then there is no difference, is
there? Please try to imagine somebody reading your posts and
attempting to extract some kind of technical objective truth
out of them.

There is a very strong technical argument for *not* putting them
in anonymous namespace. You don't want anonymous namespaces in
a header file, and I would imagine that most coding guidelines
forbid them. Since there is nothing to be gained by putting
constants in an anonymous namespace, there is no reason to make
an exception to this rule for constants.
 
S

Stephen Horne

Enums were what was used before the rules were changed to allow
the initializer in the declaration. The rule was changed
because using enums created too many problems due to the type
being wrong.

Never had that problem myself - I'm careful how I overload my integers
for reasons that are nothing to do with enum, and everything to do
with my failed portable code ideals. You never know whether int will
be considered the same type as long int and so on - even though
they're normally the same type in the set-of-values sense, and have
been since the days of 16-bit ints.

Enums are still being used - old habits die hard - it's just that it's
naughtier than it used to be.
 
I

Ian Collins

Stephen said:
Never had that problem myself - I'm careful how I overload my integers
for reasons that are nothing to do with enum, and everything to do
with my failed portable code ideals. You never know whether int will
be considered the same type as long int and so on - even though
they're normally the same type in the set-of-values sense, and have
been since the days of 16-bit ints.
Not really, long is at least 32 bit and most 64 bit systems that aren't
windows use 32 bit int and 64 bit long.
 
S

Stephen Horne

What you mean "the type is wrong"? If I defined it as a


static const short SIZE;

inside the class declaration, would the type be right?

Different, certainly.

From Stroustrup : "Each enumeration is a distinct type."

This applies to anonymous enums too, AFAIK.

Therefore, an enum doesn't match any particular integer type (other
than itself) for overloading, so casting rules apply. And then you get
into which-types-are-considered-the-same issues and so on.

For what it's worth, IMO your example was fine.
 
S

Stephen Horne

Not really, long is at least 32 bit and most 64 bit systems that aren't
windows use 32 bit int and 64 bit long.

Most platforms *are* Windows ;-)

OK, I could easily be wrong on that one.

Obviously, I rarely spell out the standard integer types directly,
except for plain int and size_t (and even size_t has caused problems).
All this vague short/long/etc nonsense first bit me a very long time
ago. Now, I don't really care how the compiler spells 64-bits, other
than when I'm adding a new #ifdef block to the relevant file.

What's the odds on "really totally enormously gigantic int" being
added in the 2050 C and C++ standards?

And how come we got the strangely sensible "bool" instead of "itty
bitty tiny int"?
 
I

Ioannis Vranos

Victor said:
Please answer the concrete question. What would be the reason to have
constants in the *anonymous* namespace as compared to the *global*
namespace? Concrete answer, please. If you don't have one, say so.


Good coding guidelines I guess. Imagine the situation



file1.cpp:


const double PI= 3.14;

namespace
{
double dpi= 2* PI;
}
 
B

Bo Persson

Victor said:
shuisheng said:
[..]
So I think the following is the right way, please confirm it. I
use PI as an example.

For global constants:

// in constants.h
const double PI = 3.14;

// in h or cpp files to use PI
#include "constants.h"
double a = PI;


For constants in namespace:

// in constants.h
namespace constants
{
const double PI = 3.14;
};

// in h or cpp files to use PI
#include "constants.h"
double d = constants::pI;


For constants in classes:

// in class.h
class A
{
public:
static const double PI;
};

// in class.cpp
const double A::pI = 3.14;

// in h and cpp files to use it.
#include "class.h"
double a = A::pI;

And I think Ioannis Vranos's way to define global constants will
bring about problems as shown in
http://msdn.microsoft.com/en-us/library/0d45ty2d(VS.80).aspx

The code you showed here is perfectly fine, and you can
declare/define any constants that way, not just of fundamental
types, AFAIC.
The contents of the web page you cited do bother me. I am not sure
what "static linkage" is; there is no such term in C++ Standard. Why
would the page say that "If you try to use a global constant in
C++ in multiple files you get an unresolved external error"? What
kind of nonsense is that?

The page just IS nonsense, as it has a "const int" in one file and an
"extern int" in another file. Of course the linker will not connect
these two. It shouldn't!


Bo Persson
 

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,196
Latest member
ScottChare

Latest Threads

Top