From everything I am reading and testing, there is no way (without a preprocessor macro) to define a constant in a shared header and ensure that each TU is not creating its own storage for that constant.
I can do this:
const int maxtt=888888;
Which is the same exactly as:
static const int maxtt=888888;
And if this header is shared, it will work but each TU gets its own copy of maxtt. I could also do this, to prevent that:
extern const int maxtt;
But then I cannot define maxtt here; that must be done in a CPP to avoid linker error.
Is my understanding correct?
Since the variable is constant, the fact that each TU gets its own copy is usually irrelevant.
In C++, constants at namespace scope are implicitly static for this reason. Often this allows for better code than if you only had a single instance with external linkage, since (if the variable is actually a constant expression) the constant can often be folded right into the usage site and doesn't need to be stored at all.
So unless you really need to take the address of the constant, or something like that, you should stick with the static version. (And as you already observed, you can force external linkage by adding extern.) Another reason may be that you're initializing dynamically and only want one call to the initializer:
// header:
extern int const n;
// one implementation:
int const n = init_function_with_side_effects();
The static construction (int const n = init(); in the header) would cause the function to be called once in every TU.
You write,
“From everything I am reading and testing, there is no way (without a preprocessor macro) to define a constant in a shared header and ensure that each TU is not creating its own storage for that constant.”
Happily that’s incorrect.
For a small integral value you can always just use an enum. The trade-off is that you can’t pass the address of an enum value, because it has no address. It’s pure value.
However, saving space for an integral value is a pretty meaningless thing to do, since it’s so small.
So, let’s consider a biggie thingy,
struct BiggyThingy
{
unsigned char zeroes[1000000];
BiggyThingy(): zeroes() {}
};
Now how can we declare a BiggyThingy constant in a header file and ensure a single one overall for the whole program?
Using an inline function.
Well the simplest is this:
inline BiggyThingy const& getBiggyThingy()
{
static BiggyThingy const theThingy;
return theThingy;
}
static BiggyThingy const& biggyThingy = getBiggyThingy();
If you don’t want a reference taking up space (like a pointer) in each translation unit, then just use the function without the notation-simplifying reference.
Using the template constant trick.
Here is another way to provide the constant, leveraging a special rule for templates instead:
template< class Dummy >
class BiggyThingyConstant_
{
public:
static BiggyThingy const value;
};
template< class Dummy >
BiggyThingy const BiggyThingyConstant_<Dummy>::value;
typedef BiggyThingyConstant_<void> BiggyThingyConstant;
which can be accessed like
foo( BiggyThingyConstant::value )
Or if you want nicer notation you can add a reference per translation unit, as for the inline function solution.
Disclaimer:
Code untouched by compiler.
But you get the ideas, I think. ;-)
This code generates a constant in the TU only if you apply any operation that requires the address of the constant.
static int maxtt = 888888;
int * pmaxtt = &maxtt; //address of constant requested.
This may work as well and avoids the linker problem (though it'll store maxtt in each TU if the address is requested):
constexpr int maxtt = 888888;
Avoid the extern construction as it can't be optimized.
If you're so worried about storage, use an enumeration:
enum { maxtt = 888888 };
Enumerators are scalar rvalues and hence do not require storage. It is illegal to say &maxtt.
Indeed, your understanding of the semantics are correct.
In practice, each translation unit might not get a copy of the storage for the integer. One reason is that the compiler might implement the value as a literal wherever it is referenced. The linker might also be smart enough to discard the storage if it finds it isn't referenced.
The compiler might not be free to use a literal for your constant. You might take a reference to that integer, or get a pointer to it. In that case, you need the storage -- and you might even need the cross-compiland uniqueness. If you take the address of your const symbol in each compilation unit, you might find that its different since each object will get a unique, static copy.
You might have a similar problem if you use an enum; your const int has storage, and you can take the address of that storage. You can't take the address of an enumerand until you store it someplace.
Related
I'm reading C++ Templates: The Complete Guide, chapter 23. Metaprogramming. At the end, it describes
the difference in using enumeration values versus static constants in metaprogramming. Consider the following two implementations of calculating Nth power of 3:
Enumeration implementation:
// primary template to compute 3 to the Nth
template<int N>
struct Pow3 {
enum { value = 3 * Pow3<N-1>::value };
};
// full specialization to end the recursion
template<>
struct Pow3<0> {
enum { value = 1 };
};
Static constant implementation:
// primary template to compute 3 to the Nth
template<int N>
struct Pow3 {
static int const value = 3 * Pow3<N-1>::value;
};
// full specialization to end the recursion
template<>
struct Pow3<0> {
static int const value = 1;
};
Right after that it says there is a drawback to the latter version. If we got a function
void foo(int const&); and pass it the result of metaprogram: foo(Pow3<7>::value); the book says:
A compiler must pass the address of Pow3<7>::value, and that forces the
compiler to instantiate and allocate the definition for the static member. As a result,
the computation is no longer limited to a pure “compile-time” effect. Enumeration values aren’t lvalues (i.e., they don’t have an address). So, when we
pass them by reference, no static memory is used. It’s almost exactly as if you passed
the computed value as a literal.
I don't understand their explanation at all to be honest. I thought in the static constant version we evaluate the result at compile time, but the actual referencing happen in run-time because we need to pass the adress. But then I don't see much difference in the former case (enum implementation) because we should have temporary materialization there (prvalue -> xvalue conversion) and since temporary objects also have the adress my thinking process fails. Also it says "no static memory is used" which I don't understand as well since static memory should refer to allocation that happen at compile-time.
Could someone explain this whole thing in greater detail?
(enum implementation) because we should have temporary materialization there (prvalue -> xvalue conversion) and since temporary objects also have the address
they do, but the temporary xvalue only exists for the duration of the function call. It's identical to passing the function an integer literal. So, an addressable object exists temporarily, at runtime, with automatic scope.
Conversely,
... that forces the compiler to instantiate and allocate the definition for the static member. As a result, the computation is no longer limited to a pure “compile-time” effect.
This static const int is an object with static storage duration. There's no temporary materialization necessary, it's an object, it existed when your program started, and you're taking a reference to it.
If you write multiple .cpp files including the header with Pow3, and they all call foo(Pow3<3>):
the enum version will emit something like foo(27) in each translation unit, with three unrelated temporary xvalues
the static version will emit a global object equivalent to const int Pow3<3>::value = 27; and each translation unit will refer to (ie, take a reference to) the same object
I suggest looking at it this way:
There is a difference between a type, an instance of a type, and the values said type can take.
In the first case you are specifying a type (an unnamed enum) with only one possible value value (which is the compile-time constant).
There are no instantiations of the type, so no memory will be used compile-time or runtime.
Every time the code refers to Pow3<N>::value, the compiler will not create an instance of the type but will instead use the constant directly.
In the second case you are instead specifying a variable value of type int, and assigning the compile-time constant to it.
This variable exists, so memory will be used.
Every time the code refers to Pow3<N>::value, the compiler will use said variable.
I'm working on a embedded system, where some calibration data is stored in the flash memory. The calibration data is stored in a struct which is placed in a special section that the linker knows to place in the flash:
struct data_block {
calibration_data mData;
uint16_t mCheckSum;
};
//Define to compile the fixed flash location for image data
const data_block __attribute__((section (".caldata"))) gCalibrationData{};
where calibration_data is another POD struct which contains the actual values.
The problem is that if I now simply write the following:
const data_block data{gCalibrationData};
if (CheckSum(&(data.mData)) == data.mCheckSum) {
//do stuff
} else {
//Error
}
this always goes to the error branch, even though the actual checksum in flash is absolutely correct (writing this a bit differently makes it work, see below).
This is of course understandable: the compiler sees a const global object, which is default-initialized, so it knows all the values, so I guess it actually optimizes out the whole if (if I debug-printf data via a uint16_t *, I actually get the correct values).
The way I think would be correct is to define
const volatile data_block __attribute__((section (".caldata"))) gCalibrationData{};
However, now I have the problem that I can't assign a volatile struct to non-volatile, i.e. const data{gCalibrationData}; does not compile. The same problem also appears if I try to access through a const volatile data_block *.
There's at least two or three ways I can make this work, and I don't like any of them:
remove the const (and volatile) qualifier from gCalibrationData. However, this is a bit of a hack based on the compiler not being clever enough to guarantee that gCalibrationData is never touched in my program, and on the other hand, I'd like to keep to const qualifier, since trying to write to gCalibrationData by assigning is a hard fault.
access gCalibrationData via const gCalibrationData * volatile pData (yes, the volatile is exactly where I mean it). Accessing through a pointer which is volatile forces the compiler to actually load the data. Again, this seems like a hack, since the pointer itself certainly isn't volatile.
give data_block and calibration_data an assignment operator taking const volatile &, and assign field by field in them. This seems to be correct from the language point of view, but then whenever calibration_data changes I need to edit the assignment operator by hand. Failing to do so will produce hard-to-detect bugs.
My question: what would be the correct way to read the calibration data? My ideal criteria would be:
the global object itself is const, to catch unintended writes.
no undefined behaviour
access by assigning the struct directly to another struct
or at least so that I'm not required to remember to assign each variable of primitive type in calibration_data, see option 3. above
bonus points for thread-safety, although in my specific case only a single thread ever reads or writes the flash (all other "threads" are interrupts).
One solution could be to declare a buffer in a separate source file, to inform the linker of size of data_block and then define gCalibrationData to be a symbol whose value is the begining of this buffer:
data_block.cpp:
//no initialization performed here, just used to
//transmit to the linker the information of the size
//and alignment of data_block
extern "C"{//simpler name mangling
[[gnu::section(".caldata")]] volatile
aligned_storage<sizeof(data_block),alignof(data_block)> datablock_buffer;
}
//then we specify that gCalibrationData refers to this buffer
extern const volatile data_block
gCalibrationData [[gnu::alias("datablock_buffer")]];
Alternatively the definition of gCalibrationData symbol can be done via a linker script:
SECTIONS{
.caldata : {
gCalibrationData = . ;
data_block.o(.caldata)
}
}
gCalibrationData is an alias to an data_block_buffer. This will not cause undefined behavior because such aliasing is permitted by the language: data_block_buffer provides storage for gCalibrationData.
Semanticaly, the extern specifier is used to say that this declaration is not a definition of the value of gCalibrationData. Nevertheless the alias attribute is a definition of the symbol for the linker.
data_block.hpp
extern const volatile data_block gCalibrationData;
//and copy must be enabled for volatile:
struct data_block{
/*...*/
data_block(const data_block&) =default;
data_block& operator=(const data_block&) =default;
data_block(const volatile data_block& other){
//the const cast means: you are responsible not to
//perform this operation while performing a rom update.
memcpy(this,const_cast<const data_block*>(&other);
}
data_block& operator=(const volatile data_block& other){
memmove(this,const_cast<const data_block*>(&other);
//or memcpy if you are sure a self assignment will never happen.
return *this;
}
};
The most practical approach would be to lose the const. By a strict reading of the standard, gCalibrationData shouldn't be allowed to be const, since writing to a const object -- regardless of who does it -- leads to undefined behavior.
Failing that, though, just define it as extern const (and, if necessary to placate the linker, put the non-extern definition in its own translation unit. That will get you your const-correctness checking, allow the compiler to, e.g., do hoisting optimizations based on the initial values of the calibration data, while still preventing it from making any specific assumptions about those values at compile time.
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.