Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 551
Malvineous Avatar asked Jan 16 '15 09:01

Malvineous


Video Answer


2 Answers

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; }
};
like image 138
Walter Avatar answered Oct 03 '22 00:10

Walter


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;
    
like image 36
Angew is no longer proud of SO Avatar answered Oct 02 '22 22:10

Angew is no longer proud of SO