I am trying to make a compile-time set of tags at most 8 chars out of constant string. For example, "abc" should become 0x6162630000000000, "" should become 0, etc.
For this, I thought I should use the fact that references to arrays do not decay to pointers and I can capture the N (size) of the const array with this:
template <size_t N>
inline constexpr uint64_t make_tag(char const (&arr)[N]) {
if (N == 1) {
return 0;
}
uint64_t result = 0;
for (size_t i = 0; (i < (N-1)) && (i<8); i++) {
result = (result << 8) | arr[i];
}
if ((N-1) < 8) {
result = result << (8 * (8 - (N-1)));
}
return result;
}
The N is captured correctly which is 1 for "" and len+1 for the rest of strings.
Here is the thing that confuses me: when doing something like
static constexpr uint64_t a0=make_tag("");
GCC 11.2 is telling me this:
<source>: In instantiation of 'constexpr uint64_t make_tag(const char (&)[N]) [with long unsigned int N = 1; uint64_t = long unsigned int]':
<source>:24:43: required from here
<source>:17:33: error: left shift count >= width of type [-Werror=shift-count-overflow]
17 | result = result << (8 * (8 - (N-1)));
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
clang does not behave like that.
For convenience, here is the compiler explorer snippet:
EDIT: if (N == 1) {...} else {...} did the trick as @Useless suggested