I can find many hits on the question on how to map an integer to a string constant, with the obvious solution
char const* strings[] = {"Foo", "Bar", ...};
Now, suppose I want the inverse: I have the string "Bar", and want 1. My strings are up to 4 characters and ascii null is not a valid value. There are 64 integers to map values to. Do I have to write a long if-else construct with string comparison or is there something better.
To clarify, I prefer the solution to not require runtime initialization, which as of C++17, makes ti impossible to use std::map
or std::unordered_map
.
My strings are up to 4 characters and ascii null is not a valid value.
With this condition, you can convert your strings into an integer, and use your favourite compile-time integer-to-integer map.
For example, with a switch
:
#include <cstddef>
#include <cstdint>
namespace detail {
constexpr std::uint64_t string_as_int(const char* string) noexcept {
std::uint64_t result = 0;
std::uint64_t i = 0;
for (; i < 4 && *string; ++string, ++i) {
result |= static_cast<std::uint64_t>(static_cast<unsigned char>(*string)) << (i * 8u);
}
return result;
}
constexpr std::uint64_t operator ""_h(const char* string, std::size_t) noexcept {
return string_as_int(string);
}
}
constexpr int lookup(const char* string) {
using detail::operator ""_h;
switch (detail::string_as_int(string)) {
case "Foo"_h: return 1;
case "Bar"_h: return 2;
default: return 0;
}
}