On 23.02.2016 0:39, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Paavo Helde <
myfir...@osa.pri.ee> spake the secret code
> <
OYOdncUI350MEVbL...@giganews.com> thusly:
>
>> No problem, in C++ we can have the same:
>>
>> enum constants: uint64_t {
>> Ann = 0x6e6e41,
>> Betty = 0x7974746542,
>> };
>>
>> Or even combine this with user literals:
>>
>> #include <iostream>
>> #include <string>
>> #include <stdint.h>
>>
>> constexpr uint64_t operator""_id(const char* p, size_t n) {
>> return static_cast<unsigned char>(*p) | (n>0 ? operator""_id(p+1, n-1)
>> : uint64_t(0))<<8;
>> }
>>
>> enum constants: uint64_t {
>> Ann = "Ann"_id,
>> Betty = "Betty"_id,
>> };
>
> For this to be visible as the string "Ann\0" in memory, doesn't this
> assume a certain byte order for integral types?
>
Yes, you are right. The problem with endianness is that the bytes are
not guaranteed to be in a strictly monotonic order. Others are claiming
that there is no standard and reliable way to find the endianness out at
compile time (for constexpr). However, I started to think isn't it
possible to reuse the user literal mechanism itself, even if it is not
good for finding out the actual endianness it should be good for the
user literals themselves.
(Warning: I do not have access to any big- or mixed-endian machines for
testing, so this may contain bugs, and certainly it can be simplified):
#include <iostream>
#include <string>
#include <stdint.h>
constexpr uint64_t operator""_idraw(const char* p, size_t n) {
return static_cast<unsigned char>(*p) | (n>0 ? operator""_idraw(p+1,
n-1): uint64_t(0))<<8;
}
constexpr uint64_t Fill64(uint64_t c) {
return c | c<<8 | c<<16 | c<<24 | c<<32 | c<<40 | c<<48 | c<<56;
}
constexpr uint64_t SelectByte(int pos) {
return
pos==0 ? "\xff"_idraw :
(pos==1 ? "\x00\xff"_idraw :
(pos==2 ? "\x00\x00\xff"_idraw :
(pos==3 ? "\x00\x00\x00\xff"_idraw :
(pos==4 ? "\x00\x00\x00\x00\xff"_idraw :
(pos==5 ? "\x00\x00\x00\x00\x00\xff"_idraw :
(pos==6 ? "\x00\x00\x00\x00\x00\x00\xff"_idraw :
(pos==7 ? "\x00\x00\x00\x00\x00\x00\x00\xff"_idraw : 0)))))));
}
constexpr uint64_t IdFromString(const char* p, size_t n, int pos) {
return (Fill64(static_cast<unsigned char>(*p)) & SelectByte(pos)) |
(n>0 ? IdFromString(p+1, n-1, pos+1) : uint64_t(0));
}
constexpr uint64_t operator""_id(const char* p, size_t n) {
return IdFromString(p, n, 0);
}
enum constants: uint64_t {
Ann = "Ann"_id,
Betty = "Betty"_id,
};
std::string StrFromId(uint64_t x) {
std::string s(reinterpret_cast<const char*>(&x), 8);
return s.substr(0, s.find(char(0)));
}
int main() {
uint64_t arr[] = {Ann, Betty, "Caroline"_id, "Delilah"_id};
for(auto x: arr) {
switch(x) {
case Ann:
std::cout << "A " << StrFromId(x) << "\n";
break;
case Betty:
std::cout << "B " << StrFromId(x) << "\n";
break;
case "Caroline"_id:
std::cout << "C " << StrFromId(x) << "\n";
break;
case "Delilah"_id:
std::cout << "D " << StrFromId(x) << "\n";
break;
}
}
}