I have recently discovered an annoying problem in some large program i am developing; i would like to understand how to fix it in a best way. I cut the code down to the following minimal example.
#include <iostream>
using std::cin;
using std::cout;
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
int main()
{
int choice;
cout << "How much stuff do you want?\n";
cin >> choice;
int stuff = (choice < 20) ? MagicNumbers::SMALL : MagicNumbers::BIG; // PROBLEM!
cout << "You got " << stuff << "\n";
return 0;
}
I get link errors in gcc 4.1.2 when compiling with -O0 or -O1 but everything is OK when compiling with -O2 or -O3. It links well using MS Visual Studio 2005 regardless of optimization options.
test.cpp:(.text+0xab): undefined reference to `MagicNumbers::SMALL'
test.cpp:(.text+0xb3): undefined reference to `MagicNumbers::BIG'
I looked at the intermediate assembly code, and yes, the non-optimized code regarded SMALL and BIG as external int variables, while the optimized one used the actual numbers. Each of the following changes fixes the problem:
Use enum instead of int for constants: enum {SMALL = 10}
Cast the constant (any one) at each usage: (int)MagicNumbers::SMALL or (int)MagicNumbers::BIG or even MagicNumbers::SMALL + 0
Use a macro: #define SMALL 10
Not use the choice operator: if (choice < 20) stuff = MagicNumbers::SMALL; else stuff = MagicNumbers::BIG;
I like the first option best (however, it's not ideal because we actually use uint32_t instead of int for these constants, and enum is synonymous with int). But what i really want to ask is: whose bug is it?
Am i the one to blame for not understanding how static integral constants work?
Should i blame gcc and hope for a fix (or maybe the latest version already has a fix, or maybe there is an obscure command-line argument to make this work)?
Meanwhile, i just compile my code with optimizations, and it's a pain to debug :-O3
This is a known issue. The Standard is to blame or you for not providing a definition of the statics. Depending on your point of view :)
In spite of the conventional advice, I have found that static const int ... invariably gives me more headaches than good old enum { BIG = 100, SMALL = 10 };. And with C++11 providing strongly-typed enums, I now have even less cause to use static const int ....
Static data members don't work like that in C++:
Static data members are not part of
objects of a given class type; they
are separate objects. As a result, the
declaration of a static data member is
not considered a definition. The data
member is declared in class scope, but
definition is performed at file scope.
These static members have external
linkage.
You're only declaring those constants, even though you're initializing them. You still have to define them at namespace scope:
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
const int MagicNumbers::BIG;
const int MagicNumbers::SMALL;
That will get rid of the link errors.
Heh, according to the C++ standard, 9.4.2 (class.static.data):
If a static data member is of const
literal type, its declaration in the
class definition can specify a
brace-or-equal-initializer in which
every initializer-clause that is an
assignment-expression is a constant
expression. A static data member of
literal type can be declared in the
class definition with the constexpr
specifier; if so, its declaration
shall specify a
brace-or-equal-initializer in which
every initializer-clause that is an
assignment-expression is a constant
expression. [ Note: In both these
cases, the member may appear in
constant expressions. —end note ] The
member shall still be defined in a
namespace scope if it is used in the
program and the namespace scope
definition shall not contain an
initializer.
So the declaration is correct, but you still need to have a definition somewhere. I always thought you could skill the definition, but I suppose that isn't standard conforming.
I'm new to C++, but I think that your class declaration only declares that those static members exist, you still need to define them somewhere:
class MagicNumbers
{
public:
static const int BIG;
static const int SMALL;
};
const int MagicNumbers::BIG = 100;
const int MagicNumbers::SMALL = 10;
The higher optimisation levels probably include a level of static analysis thorough enough to determine that BIG and SMALL can be exchanged with their actual values and not to give them any actual storage (the semantics will be the same), so defining these variables in this circumstance would be redundant, hence it links OK.
I'd be hard pressed to assert that it's anyone's bug.
Static const integrals given values at point of declaration are not variables, they're constant expressions. For there to be a variable you still need to define it.
The rules wrt the ternary operator are pretty absurdly complex, probably necessarily so, and actually doesn't really say anything about constant expressions, only rvalues; obviously the compiler thinks they should be variables unless optimization is cranked way up. I think it's free to interpret the expression either way (as a constant expression or as variable).
You still need to allocate space for them somewhere:
class MagicNumbers
{
public:
static const int BIG = 100;
static const int SMALL = 10;
};
const int MagicNumbers::BIG;
const int MagicNumbers::SMALL;
Why are your magic numbers in a class?
namespace MagicNumbers {
const int BIG = 100;
const int SMALL = 10;
}
Problem solved without needing to worry about flaws in the C++ standard.
Related
Consider code like the following, where the literal some_magic_int (e.g. 3) is given a name just to make a bit clearer what constant it represents:
void f() {
static constexpr int this_variable{some_magic_int};
do_something_with(this_variable);
}
int main() {
// ...
f();
// ...
}
I'm pretty sure constexpr has to be here: some_magic_int is literal, so it never changes, and I'm giving it a name just for clarity, not to give a mean to change it, so it should be at least const; then why not constexpr to have it at compile-time?
But what about static? Is it just unnecessary? Or is it detrimental? If so, why? And also, does it have any observable effect, when paired with constexpr in the declaration of a local variable?
As regards the question to which this is marked as duplicate of, it is about static constexpr int x [] = {}, and not static constexpr int x {}. This highlights at least one difference between that case (attributes applying to x pointer vs attributes applied to *x pointee) and my case (there's no pointer).
Furthermore, once I add constexpr to the specifier of a local variable (where it makes sense, e.g. to a int), I'm saying that variable is compile-time known. Why in the world doesn't that imply that no run-time entity is needed whatsoever?
The standard doesn’t actually ever talk about compile-time anything except to say that types are checked and templates are instantiated before execution. That means that this program must be diagnosed (not “rejected”!) even though the non-constant array length and template argument are never “used” and might plausibly be ignored by an interpreter:
template<int> void f() {}
int main(int argc,char **argv) {
if(false) {
int buf[argc]; // accepted by a common extension
f<argc>();
}
}
Beyond that, the semantics are that every evaluation is part of the ordinary execution of the program and constant folding is just an as-if optimization like any other. (After all, we can optimize argc*2*3*4 even though it contains no non-literal subexpression that could be a constant expression.) For constant expressions, this is largely unobservable because constant evaluation can’t have side effects (which also avoids interactions among constant-initialized non-block variables). It can, however, make a difference via the address of the local variable:
bool introspect(const int *p=nullptr) {
constexpr int x=0;
return p ? p==&x : introspect(&x); // always false
}
That the compiler must make such variables occupy memory if their address escapes is much of the content of the answers to the previously marked duplicate. It therefore makes sense to prefer static except perhaps when the object is large and its address doesn’t matter (e.g., for use as a template argument or via recursion).
I'm just wondering whether sentences like const int N=10 will be executed at compilation time. The reason I'm asking is because that the following code will work.
int main()
{
const int N=10;
int a[N]={};
return 0;
}
But this one wouldn't.
int main()
{
int N=10;
int a[N]={};
return 0;
}
The compiler must generate code "as if" the expression was evaluated at
compile time, but the const itself isn't sufficient for this. In
order to be used as the dimension of an array, for example, expression
N must be a "constant integral expression". A const int is
a constant integral expresion only if it is initialized with a constant
integral expression, and the initialization is visible to the compiler.
(Something like extern int const N;, for example, can't be used in
a constant integral expression.)
To be a constant integral expression, however, the variable must be
const; in your second example, the behavior of the compiler and the
resulting program must be "as if" the expression were only evaluated at
runtime (which means that it cannot be used as the dimension of an
array). In practice, at least with optimization, the compiler likely
would evaluate N at compile time, but it still has to pretend it
can't, and refuse to compile the code.
The compiler will probably evaluate both of the examples you provided at compile time, since even though the int N = 10; isn't const, you're not changing it anywhere and you're only assigning a constant value to it, which means the compiler can optimize this.
I recommend you take a look at the constexpr keyword introduced in C++11, which is exactly about being able to evaluate things at compile time.
Compilers will resolve const variables to literals at compile time (and also const expressions, see constant folding). The reason that the first method works is that compiler knows how much space to allocate (10*sizeof(int)) to a in the first method. In the second method the value of N is not known at compile time, and as such there is no way for the compiler to know how much space to allocate for a. Hope that helps.
This sort of thing is an implementation detail that technically is up to the compiler to choose. It could be different on different platforms.
In practice, with the most common compilers:
const int sometimes is and sometimes isn't baked at compile time. For example, the compiler clearly can't hardcode the value of a below into the object file:
int foo( int x )
{
const int a = x+ 1;
return a * 2;
}
In that function, const means it is only constant within the scope of foo(), but it is still a local stack variable.
On the other hand, const int x = 5 seems to be a literal that is usually resolved at compile time by GCC and MSVC (except sometimes they don't turn it into a literal for reasons unclear). I've seen some other compilers that won't turn it into a literal, and always put const int on the stack like an ordinary local variable.
const static int is different, because its scope is static, which means it outlives the function it is declared in, which means it will never change over the life of the program. Every compiler I've ever worked with has turned const static primitives into compile-time literals.
Objects with constructors, however, will still need to be initialized at runtime; so
class Foo {
Foo() : { CallGlobalFunction(); }
};
const static Foo g_whatever;
cannot be optimized into a literal by the compiler.
What are the best ways to declare and define global constants in C++? I am mostly interested in C++11 standard as it fixes a lot in this regard.
[EDIT (clarification)]: in this question "global constant" denotes constant variable or function that is known at compile time in any scope. Global constant must be accessible from more than one translation unit. It is not necessarily constexpr-style constant - can be something like const std::map<int, std::string> m = { { 1, "U" }, { 5, "V" } }; or const std::map<int, std::string> * mAddr() { return & m; }. I do not touch preferable good-style scope or name for constant in this question. Let us leave these matters for another question. [END_EDIT]
I want to know answers for all the different cases, so let us assume that T is one of the following:
typedef int T; // 1
typedef long double T; // 2
typedef std::array<char, 1> T; // 3
typedef std::array<long, 1000> T; // 4
typedef std::string T; // 5
typedef QString T; // 6
class T {
// unspecified amount of code
}; // 7
// Something special
// not mentioned above? // 8
I believe that there is no big semantic (I do not discuss good naming or scope style here) difference between the 3 possible scopes:
// header.hpp
extern const T tv;
T tf(); // Global
namespace Nm {
extern const T tv;
T tf(); // Namespace
}
struct Cl {
static const T tv;
static T tf(); // Class
};
But if choosing better way from alternatives below depends on the difference between above declaration scopes, please point it out.
Consider also the case when function call is used in constant definition, e.g. <some value>==f();. How would calling a function in constant initialization influence choosing between alternatives?
Let us consider T with constexpr constructor first.
Obvious alternatives are:
// header.hpp
namespace Ns {
constexpr T A = <some value>;
constexpr T B() { return <some value>; }
inline const T & C() { static constexpr T t = <some value>; return t; }
const T & D();
}
// source.cpp
const T & Ns::D() { static constexpr T t = <some value>; return t; }
I believe that A and B are most suitable for small T (such that having multiple instances or copying it at runtime is not a problem), e.g. 1-3, sometimes 7. C and D are better if T is large, e.g. 4, sometimes 7.
T without constexpr constructor. Alternatives:
// header.hpp
namespace Ns {
extern const T a;
inline T b() { return <some value>; }
inline const T & c() { static const T t = <some value>; return t; }
const T & d();
}
// source.cpp
extern const T Ns::a = <some value>;
const T & Ns::d() { static const T t = <some value>; return t; }
I would not normally use a because of static initialization order fiasco. As far as I know, b, c and d are perfectly safe, even thread-safe since C++11. b does not seem to be a good choice unless T has a very cheap constructor, which is uncommon for non-constexpr constructors. I can name one advantage of c over d - no function call (run-time performance); one advantage of d over c - less recompiling when constant's value is changed (these advantages also apply to C and D). I am sure that I missed a lot of reasoning here. Provide other considerations in answers please.
If you want to modify / test the above code, you can use my test files (just header.hpp, source.cpp with compilable versions of above code fragments and main.cpp that prints constants from header.hpp): https://docs.google.com/uc?export=download&id=0B0F-aqLyFk_PVUtSRnZWWnd4Tjg
I believe that there is no big difference between the following declaration locations:
This is wrong in a lot of ways.
The first declaration pollutes the global namespace; you have taken the name "tv" from ever being used again without the possibility of misunderstandings. This can cause shadowing warnings, it can cause linker errors, it can cause all sorts of confusion to anyone who uses your header. It can also cause problems to someone who doesn't use your header, by causing a collision with someone else who also happens to use your variable name as a global.
Such an approach is not recommended in modern C++, but is ubiquitous in C, and therefore leads to much use of the static keyword for "global" variables in a .c file (file scope).
The second declares pollutes a namespace; this is much less of an issue, as namespaces are freely renamable and can be made at no cost. As long as two projects use their own, relatively specific namespace, no collisions will occur. In the case where such collisions do occur, the namespaces for each can be renamed to avoid any issues.
This is more modern, C++03 style, and C++11 expands this tactic considerably with renaming of templates.
The third approach is a struct, not a class; they have differences, especially if you want to maintain compatibility with C. The benefits of a class scope compound on the namespace scope; not only can you easily encapsulate multiple things and use a specific name, you can also increase encapsulation via methods and information hiding, greatly expanding how useful your code is. This is mostly the benefit of classes, irrespective of scoping benefits.
You should almost certainly not use the first one, unless your functions and variables are very broad and STL/STD like, or your program is very small and not likely to be embedded or reused.
Let's now look at your cases.
The size of the constructor, if it returns a constant expression, is unimportant; all of the code ought to be executable at compile time. This means the complexity is not meaningful; it will always compile to a single, constant, return value. You should almost certainly never use C or D; all that does is make the optimizations of constexpr not work. I would use whichever of A and B looks more elegant, probably a simple assignment would be A, and a complex constant expression would be B.
None of these are necessarily thread safe; the content of the constructor would determine both thread and exception safety, and it is quite easy to make any of these statements not thread safe. In fact, A is most likely to be thread safe; as long as the object is not accessed until main is called, it should be fully formed; the same cannot be said of any of your other examples. As for your analysis of B, in my experience, most constructors (especially exception safe ones) are cheap as they avoid allocation. In such cases, there's unlikely to be much difference between any of your cases.
I would highly recommend you stop attempting micro-optimizations like this and perhaps get a more solid understanding of C++ idioms. Most of the things you are trying to do here are unlikely to result in any increase in performance.
You didn't mention an important option:
namespace
{
const T t = .....;
};
Now there are no name collision issues.
This isn't appropriate if T is something you only want to construct once. But having a large "global" object, const or not, is something you really want to avoid. It breaks encapsulation, and also introduces the static initialization order fiasco into your code.
I've never had the need for a large extern const object. If I need a large hardcoded lookup table for example, then I write a function (perhaps as a class member) that looks up the table; and the table is local to the unit with the implementation of that function.
In my code that seems to call for a large non-const global object, I actually have a function,
namespace MyStuff
{
T &get_global_T();
}
which constructs the object on first use. (Actually, the object itself is hidden in one unit, and T is a helper class that specifies an interface; so I can mess around with the object's details and not disturb any code that is using it).
1
In case A there is a difference between global or namespace scope (internal linkage) and class scope (external linkage). So
// header.hpp
constexpr T A = <some value>; // internal linkage
namespace Nm { constexpr T A = <some value>; } // internal linkage
class Cl { public: static constexpr T A = <some value>; }; // not enough!
Consider the following usage:
// user.cpp
std::cout << A << Nm::A << Cl::A; // ok
std::cout << &A << &Nm::A; // ok
std::cout << &Cl::A; // linker error: undefined reference to `Cl::A'
Placing Cl::A definition in source.cpp (in addition to the above Cl::A declaration) eliminates this error:
// source.cpp
constexpr T Cl::A;
External linkage means that there would always be only one instance of Cl::A. So Cl::A seems to be a very good candidate for large T. However: can we be sure that static initialization order fiasco would not present itself in this case? I believe that the answer is yes, because Cl::A is constructed at compile-time.
I have tested A, B, a alternatives with g++ 4.8.2 and 4.9.0, clang++ 3.4 on GNU/Linux platform. The results for three translation units:
A in class scope with definition in source.cpp was both immune to fiasco and had the same address in all translation units even at compile-time.
A in namespace or global scope had 3 different addresses both for large array and constexpr const char * A = "A"; (because of internal linkage).
B (std::array<long double, 100>) in any scope had 2 different addresses (address was the same in 2 translation units); additionally all 3 B addresses suggested some different memory location (they were much bigger than other addresses) - I suspect that array was copied in memory at runtime.
a when used with constexpr types T, e.g. int, const char *, std::array, AND initialized with constexpr expression in source.cpp, was as good as A: immune to fiasco and had the same address in all translation units. If constant of constexpr type T is initialized with non-constexpr, e.g. std::time(nullptr), and used before initialization, it would contain default value (for example, 0 for int). It means that constant's value can depend on static initialization order in this case. So, do not initialize a with non-constexpr value!
The bottom line
prefer A in class scope for any constexpr constant in most cases because it combines perfect safety, simplicity, memory saving and performance.
a (initialized with constexpr value in source.cpp!) should be used if namespace scope is preferable or it is desirable to avoid initialization in header.hpp (in order to reduce dependencies and compilation time). a has one disadvantage compared to A: it can be used in compile-time expressions only in source.cpp and only after initialization.
B should be used for small T in some cases: when namespace scope is preferable or template compile-time constant is needed (pi for example). Also B can be used when constant's value is rarely used or used only in exceptional situations, e.g. error messages.
Other alternatives should almost never be used as they would rarely suit better than all 3 before-mentioned ways.
A in namespace scope should not be used because it can potentially lead to N instances of constant, hence consume sizeof(T) * N bytes of memory and cause cache misses. Here N equals to the number of translation units that include header.hpp. As noted in this proposal, A in namespace scope can violate ODR if used in inline function.
C could be used for big T (B is usually better for small T) in 2 rare scenarios: when function call is preferable; when namespace scope AND initializing in header is preferable.
D could be used when function call AND initializing in source file is preferable.
The only shortcoming of C compared to A and B - its return value can not be used in compile-time expression. D suffers from the same shortcoming and another one: function call run-time performance penalty (because it can not be inlined).
2
Avoid using non-constexpr a because of static initialization order fiasco. Consider a only in case of sure bottleneck. Otherwise, safety is more important than small performance gain. b, c and d are much safer. However c and d have 2 safety requirements:
for (auto f : {all c and d-like functions}) {
T constructor must not call f because if the initialization of static local variable recursively enters the block in which the variable is being initialized, the behavior is undefined. This is not difficult to ensure.
For each class X such that X::~X calls f and there is a statically initialized X object: X::X must call f. The reason is that otherwise static const T from f could be constructed after and therefore destructed before global X object; then X::~X would cause UB. This requirement is much more difficult to guarantee than the previous one. So it almost prohibits global or static local variables with complicated destructors that use global constants. If destructor of statically initialized variable is not complicated, e.g. uses f() for logging purposes, then placing f(); in the corresponding constructor ensures safety.
}
Note: these 2 requirements do not apply to C and D:
the recursive call to f would not compile;
static constexpr T constants in C and D are constructed at compile time - before any non-trivial variable is constructed, so they are destructed after all non-trivial variables' destruction (destructors are called in reverse order).
Note 2: C++ FAQ suggests a different implementation of c and d, which does not impose the second safety requirement. However in this case static constant is never destructed, which can interfere with memory leak detection, e.g. Valgrind diagnostic. Memory leaks, however benign, should be avoided. So these modified versions of c and d should be used only in exceptional situations.
One more alternative to consider here is a constant with internal linkage:
// header.hpp
namespace Ns { namespace { const T a1 = <some value>; } }
This approach has the same big downside as A in namespace scope: internal linkage can create as many copies of a1 as the number of translation units that include header.hpp. It can also violate ODR in the same way as A. However, since other options for non-constexpr are not as good as for constexpr constants, this alternative actually could have some rare use. BUT: this "solution" is still prone to static initialization order fiasco in case when a1 is used in public function which in turn is used for initialization of a global object. So introducing internal linkage does not solve the problem - just hides it, makes it less likely, probably more difficult to locate and fix.
The bottom line
c provides the best performance and saves memory because it facilitates reusing exactly one T instance and can be inlined, so it should be used in most cases.
d is as good as c for saving memory but is worse for performance as it would never be inlined. However d can be used to reduce compilation time.
consider b for small types or for rarely used constants (in rarely-used-constant case its definition can be moved to source.cpp to avoid recompilation on change). Also b is the only solution if safety requirements for c and d can not be satisfied. b is definitely not good for large T if constant is used often, because the constant has to be constructed each time b is called.
Note: there is another compile-time issue of inline functions and variables initialized in header.hpp. If constant's definition depends on another constant declared in a different header bad.h, and header bad.h should not be included in header.hpp, then D, d, a and modified b (with definition moved to source.cpp) are the only alternatives.
The typical way to define an integer constant to use inside a function is:
const int NumbeOfElements = 10;
the same for using within a class:
class Class {
...
static const int NumberOfElements = 10;
};
It can then be used as a fixed-size array bound which means it is known at compile time.
Long ago compilers didn't support the latter syntax and that's why enums were used:
enum NumberOfElementsEnum { NumberOfElements = 10; }
Now with almost every widely used compiler supporting both the in-function const int and the in-class static const int syntax is there any reason to use the enum for this purpose?
The reason is mainly brevity. First of all, an enum can be anonymous:
class foo {
enum { bar = 1 };
};
This effectively introduces bar as an integral constant. Note that the above is shorter than static const int.
Also, no-one could possibly write &bar if it's an enum member. If you do this:
class foo {
static const int bar = 1;
}
and then the client of your class does this:
printf("%p", &foo::bar);
then he will get a compile-time linker error that foo::bar is not defined (because, well, as an lvalue, it's not). In practice, with the Standard as it currently stands, anywhere bar is used where an integral constant expression is not required (i.e. where it is merely allowed), it requires an out-of-class definition of foo::bar. The places where such an expression is required are: enum initializers, case labels, array size in types (excepting new[]), and template arguments of integral types. Thus, using bar anywhere else technically requires a definition. See C++ Core Language Active Issue 712 for more info - there are no proposed resolutions as of yet.
In practice, most compilers these days are more lenient about this, and will let you get away with most "common sense" uses of static const int variables without requiring a definition. However, the corner cases may differ, however, so many consider it to be better to just use anonymous enum, for which everything is crystal clear, and there's no ambiguity at all.
Defining static constants directly in the class definition is a later addition to C++ and many still stick to the older workaround of using an enum for that. There might even be a few older compilers still in use which don't support static constants directly defined in class definitions.
Use of enum have one advantage. An enum type is a type, so if you define, for example:
enum EnumType { EnumValue1 = 10, EnumValue2 = 20 ... };
and you have a function like:
void Function1(EnumType Value)
the compiler checks that you are passing a member of the enum EnumType to the function, so only valid values for parameter Value would be EnumValue1 and EnumValue2. If you use constants and change the function to
void Function1(int Value)
the compiler checks that you are passing an int (any int, a constant, variable or literal) to the function.
Enum types are good for grouping related const-values. For only one const value, I do not see any advantage.
In your case, I'd use a constant as well. However, there are other cases where I might be adding other, related constants. Like this:
const int TextFile = 1; // XXX Maybe add other constants for binary files etc.?
In such cases, I use an enum right away with a single value, like this:
enum FileType {
TextFile = 1
// XXX Maybe add other values for binary files etc.?
}
The reason is that the compiler can then issue warnings when I'm using the constant value in switch expressions, as in:
FileType type;
// ...
switch ( type ) {
case TextFile:
// ...
}
In case I decide to add another constant value which is related to the existing value (a different type of file, in this example), virtually all compilers will issue a warning since the new value is not handled in the switch statement.
If I had used 'int' and constants instead, the compiler wouldn't have a chance to issue warnings.
The only reason for using the "enum hack" is that old compilers do not support in-class const definitions, as you say in your question. So, unless you suspect that your code will be ported to an old compiler, you should use const where const is due.
I think that there's no reason to use an enum, and that it's actually better to use a static const int for this purpose, since an enum has its own type (even if implicitly convertible to an integer).
There is a difference between those two. Enums don't have an adress as far as I know. static const ints do though. So if someone takes the adress of the const static int, casts away the const, he can modify the value (although the compiler might ignore the change because he thinks it's const). This is of course pure evil and you should not do it - but the compiler can't prevent it. This can't happen with enums.
And of course - if you (for some reason) need the adress of that const, you need the static const int.
In short - enum is an rvalue while const static int is an lvalue. See http://www.embedded.com/story/OEG20011129S0065 for more details.
Well, the portability is a good reason for using enum. It is great, because you don't have to worry whether your compiler supports "static const int S = 10" or not...
Also, as far as I remember, static variable must be defined somewhere, as well as declared, and the enum value must be declared only.
bottom line - use const.
more details:
I'm not a c++ expert, but this seems a more general design question.
If it's not a must, and you think there's a very low/non-existent probability that the enum will grow to have more then one value, then use a regular const.
even if you are wrong and at some point in the future there will be more values, making an enum the right choice - a simple refactoring and you change you const to enum.
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
return A::B::b;
}
The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14);
We need a definition for a in addition to the declaration.
Can anyone explain why this is an exception?
C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).
Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.
For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?
By really pedantic rules, yes, your code needs a definition for that static integer.
But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.
The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.
In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
int *p = &A::B::b;
}
No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.
const int A::B::b;
Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.
The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.
However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795
So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)
So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.
In general, most (and recent) C++ compilers allow static const ints
You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.