C++ convert string literal to multi-character literal at compile time

462 views Asked by At

Basically, if I have this string:

"abcd"

I want to end up with the equivalent of:

'abcd'

at compile time. I have tried using macros, preprocessor magic, and Microsoft's charize operator (#@), but none of them work correctly. The end result should allow me to do something like this:

template <long N> struct some_type {};
long whatever = STR_TO_MULTI_CHAR_LITERAL("abcd");
some_type<whatever> xyz;
2

There are 2 answers

2
CS Pei On

Let us assume that we can forget about big/little endian for now, you could use a constexpr union like

union dirty_hack {
    long l;
    char[4] chars;
};

If we need to consider endian, it becomes more complex. Also size of long could be 8, not 4.

Another thought, if long is 32bit, char32_t char4b = U'\UAABBFFFF' is supported in C++11. But then you need figure out the map from A to 45 (hex value of A). Then cast char4b to long.

1
ecatmur On

If you can compile in C++11 mode (or above), then you're allowed to index into string literals at constant-expression time:

#define STR_TO_MULTI_CHAR_LITERAL(s)                 \
    (sizeof(s) == 5                                  \
        ? s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3] \
        : throw "wrong length")
some_type<STR_TO_MULTI_CHAR_LITERAL("abcd")> xyz;

That said, if you're allowed to use C++11 mode you should be able to use constexpr as well:

constexpr std::int32_t strToMultiCharLiteral(char const (&s)[5]) {
    return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
}
some_type<strToMultiCharLiteral("abcd")> xyz;

You can even write a user-defined string literal:

constexpr std::int32_t operator""_multiCharLiteral(char const *s, std::size_t len)
{
  return len == 4 ? s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]
    : throw "wrong length";
}
some_type<"abcd"_multiCharLiteral> xyz;