问题
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?
回答1:
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.
回答2:
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.
回答3:
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.
来源:https://stackoverflow.com/questions/37259807/static-constexpr-int-vs-old-fashioned-enum-when-and-why