This is maybe a basic question, but I cannot see the response by myself right now.
Consider the following code:
template<bool b>
struct T {
static constexpr int value = (b ? 42 : 0);
};
template<bool b>
struct U {
enum { value = (b ? 42 : 0) };
};
int main() {
static_assert(T<true>::value == 42, "!");
static_assert(T<false>::value == 0, "!");
static_assert(U<true>::value == 42, "!");
static_assert(U<false>::value == 0, "!");
}
I'm used to using structs like T
, but more than once I've seen structs like U
used for the same purpose (mostly traits definition).
As far as I can see, they are both resolved at compile time and they solve almost the same problem, but it seems to me that T
is far more readable than U
(well, I know, my personal opinion).
My question is pretty simple: is there any technical reason for which one solution is better than the other one?
Even more, is there any case for which one of them is not a viable solution?
A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.
As the answer by SergeyA indicates, enum are true constants.
const applies for variables, and prevents them from being modified in your code. constexpr tells the compiler that this expression results in a compile time constant value, so it can be used in places like array lengths, assigning to const variables, etc.
It may contain local variable declarations, but the variable must be initialized. It must be a literal type, and can't be static or thread-local. The locally declared variable isn't required to be const , and may mutate. A constexpr non- static member function isn't required to be implicitly const .
Please note, answer below is not applicable for C++ 17 and later.
There will be no noticeable difference for integral constants when used like this.
However, enum
is actually better, because it is a true named constant. constexpr
integral constant is an object which can be, for example, ODR-used - and that would result in linking errors.
#include <iostream>
struct T {
static constexpr int i = 42;
enum : int {x = 42};
};
void check(const int& z) {
std::cout << "Check: " << z << "\n";
}
int main() {
// check(T::i); // Uncommenting this will lead to link error
check(T::x);
}
When check(T::i)
is uncommented, the program can not be linked:
/tmp/ccZoETx7.o
: In function `main
':ccc.cpp
:(.text+0x45
): undefined reference to `T::i
'collect2
: error:ld
returned1
exit status
However, the true enum
always works.
I suspect it's legacy code.
enum { value = (b ? 42 : 0) };
is valid code in C++03 as well as C++11.
static constexpr int value = (b ? 42 : 0);
is valid only in C++11.
Even more, is there any case for which one of them is not a viable solution?
Both are viable solutions in C++11. The choice of which one to use depends on a team. It's going to be a matter of a policy decision.
As the answer by SergeyA indicates, enum
are true constants. You cannot ODR-use them. You can ODR-use a constexpr
. Depending on which of these is desirable for your application, you can decide whether to use enum
s or constexpr
s.
The currently accepted answer by SergeyA no longer holds as of C++17 (Definitions and ODR).
Every declaration is a definition, except for the following:
- ...
- (deprecated) Namespace scope declaration of a static data member that was defined within the class with the constexpr specifier
struct S {
static constexpr int x = 42; // implicitly inline, defines S::x
};
constexpr int S::x; // declares S::x, not a redefinition
Hence, as of C++17, I would use the static constexpr definition which is more expressive than the enum.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With