tags:

views:

145

answers:

3

How many different ways are there to define constants in C or C++?

I am already aware of using the const keyword and the #define directive. I heard somewhere that there are two more ways to define constants, but I've never seen any others. Are there any others?

+1  A: 

In C, there are numeric constants and string literals (for example int i = 5, 5 is a constant) Maybe that's what they meant.

bde
A constant is different from a literal.
Daniel DiPaolo
@Daniel DiPaolo: In C++ it is different. In C constant *is* literal. More precisely, in C the term *literal* is only used with string literals. Numerical literals are called *constants* in C.
AndreyT
+6  A: 

enum, as in enum { some_constant= 2 };

EDIT: I also forgot the additions of constexpr and user defined literals in the C++0x standard. So there are actually three additional ways.

MSN
Could you give examples to the latter two?
Péter Török
@Péter, I could, but I don't have access to a working C++0x compiler that supports either, so it would just be guesswork.
MSN
+2  A: 

For the basic informal meaning of "constant" you have #define, const and enum, as already mentioned by other answers.

But at least as I'm writing this, nobody has yet discussed how to use them.

First, I'm sure you know that Macros Are Evil, so I shall not belabor the point: just say "no" to #define (as a means of defining constants).

Second, the enum comes in handy when you need to define a constant static member of integral type, in code that should be portable to older compilers.

Third, for the formal meaning of "define" there is a perhaps very surprising subtlety:

struct Blah
{
    static int const x = 42;     // This is just a declaration, not a definition.
};

int const Blah::x;               // This is a definition (yes!).

int main()
{
    // Use Blah::x here.
}

Part of the subtlety is the exchange of the visual form of pure declaration versus definition. In just about any other context it's the declaration with initialization that is also the definition. But not for this static member of integral type!

And part of the subtlety is that without the definition, somewhere, you can't formally take the address of Blah::x; it's the definition that, formally, gives it storage.

And, part of the subtlety is that for no good reason other than historical accident, you can only do the above for integral types, not for e.g. double, or a string, whatever.

struct Blah
{
    static double const x = 3.14;  // !CAN NOT DO THIS IN C++98.
};

To effectively create a member constant of, say, type double, you can use the templated constant idiom as a workaround. Effectively doing the compiler's job, what it in principle could have rewritten the above as. It goes like this:

template< class Dummy >
struct BlahConstants
{
    static double const x;
};

template< class Dummy >
double const BlahConstants< Dummy >::x = 3.14;

struct Blah
    : BlahConstants< void >
{
    // Whatever.
};

int main()
{
    // Use Blah::x here.
}

For example, you might want to employ that trick for defining class Blah completely in a header file.

It works due to special support for class templates -- because without that special rule, it would be practically impossible to define class templates with static member constants, in header files.

Cheers & hth.,

Alf P. Steinbach
+1 for the extensive explanation.
Péter Török