Effective C++ item 2: Prefer consts, enums, and inlines to #defines.

Here is an example for enum hack:

1
2
3
4
5
6
class Foo
{
private:
enum{BAR = 100};
....
};

To limit the scope of a constant to a class, we have to make it a member. And to ensure there’s at most one copy of the constant, we must make it a static member:

1
2
3
4
5
6
class Foo
{
private:
static const double RATIO = 1.5;
....
};

Above is a declaration for RATIO, not a definition. C++ requires that we provide a definition for anything we use, but class-specific constants that are static and of integral type(e.g., integers, doubles, bools) are an exception. As long as we don’t take their address, we can declare them and use them without providing a definition. If you do want to take the address, then provide a definition like this:

1
const double Foo::RATIO;

We put this in a.cpp file not a.h file. Because the initial value of class constants is provided where the constant is declared, no initial value is permitted at the point of definition.

1
2
3
4
5
6
class Foo
{
private:
static const std::string BAR;
....
};
1
const std::string Foo::BAR = "bar";

So if you define:

1
#define CALL_WITH_MAX(a,b) f((a) > (b) ? a : b)

and you will get unexpected behavior:

1
2
3
int a = 5, b = 0;
CALL_WITH_MAX(++a, b); //a is incremented twice
CALL_WITH_MAX(++a, b + 10); //a is incremented once

Reference:
“Effective C++” Third Edition by Scott Meyers.