Malvineous
Malvineous

Reputation: 27320

How to define compile-time (static) constant inside a C++ class?

I have some constants that only need to be used at compile-time to simplify code, so I don't need the actual variables available at runtime.

Traditionally the way this was done was with #define NAME 123 but I would like a type-safe alternative.

Outside of classes you can const int name = 123; which works fine, but it doesn't seem possible to put this inside a class. For example this:

class Example {
    public:
        const double usPerSec = 1000000.0;
};
double usOneMinute = 60 * Tempo::usPerSec;

Works with Visual C++, but doesn't work with GCC:

error: non-static const member ‘const double Example::usPerSec’,
  can’t use default assignment operator

You can fix it by making it static, but then Visual C++ complains:

error C2864: 'Example::usPerSec' : a static data member with an in-class
  initializer must have non-volatile const integral type
    type is 'const double'

I'm guessing this means VC++ will only accept static const int.

I want to avoid setting the value in the constructor because then I need an instance of the class at runtime in order to access the value, whereas really I want it all handled at compile time like it is with #define.

So how can I define a constant as a double inside a class, without resorting to making it global or using #define, that will work without having an instance of the class, and that will function with major C++03 compilers?

Upvotes: 5

Views: 7332

Answers (5)

TonyK
TonyK

Reputation: 17114

If I were you I would put it in a namespace:

namespace MyExampleNamespace {
    const double usPerSec = 1000000.0;
}
double usOneMinute = 60 * MyExampleNamespace::usPerSec;

Upvotes: 2

Walter
Walter

Reputation: 45424

There is a difference here between integral and other types. For integral types you can always define them as const static members as in

struct Example
{
    const static int name = 123;  // added 'static' to code in text of question
    const static unsigned usPerSec = 1000000;
};

For non-integral types, such as double in your example, the situation is more complicated. Since 2011 (using compiler option std=c++11 with most compilers), you can simply do this:

struct Example
{
    constexpr static double usPerSec = 1000000.0;
};

But with gcc, this

struct Example
{
    const static double usPerSec = 1000000.0;
};

should work also in C++03 (it's a GNU extension).

However, the standard approach in C++03, which is also used by the standard library itself (for example in std::numeric_limits<>), is a static member function

struct Example
{
    static double usPerSec() { return 1000000.0; }
};

Upvotes: 10

Pankaj Bansal
Pankaj Bansal

Reputation: 919

You have to make it static const and then give it value outside class. Don't do it inside constructor. You don't have to make make instance

class Example {
public:
    static const double usPerSec;

};

double Example::usPerSec = 1000000.0;

Now you can use it anywhere without making any instance of class

double someVar = Example::usPerSec;

Upvotes: 1

I see two possible approaches with C++03:

  1. Use a static member function and rely on inlining:

    class Example {
        public:
            static double usPerSec() { return 1000000.0; }
    };
    double usOneMinute = 60 * Example::usPerSec();
    
  2. Use a static data member and resign on constant folding (the value using the constant will be computed at runtime):

    class Example {
        public:
            static const double usPerSec;
    };
    double usOneMinute = 60 * Example::usPerSec;
    
    // Somewhere in one .cpp
    const double Example::usPerSec = 1000000.0;
    

Upvotes: 4

MichaelCMS
MichaelCMS

Reputation: 4763

This code works on both vc++ and gcc :

class Example {
public:
    static const double usPerSec ;
};
const double Example::usPerSec=10000.0;
double usOneMinute = 60 * Example::usPerSec;

Upvotes: 1

Related Questions