在编译时将C++字符串字面值转换为多字符字面值

3
基本上,如果我有这个字符串:
"abcd"

我希望最终得到类似于以下内容的翻译:
'abcd'

在编译时。我已经尝试使用宏、预处理器技巧和微软的charize运算符(#@),但它们都不能正确地工作。最终结果应该允许我像这样做:

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

“Microsoft的charize运算符” 那么您正在使用MSVC编译器?哪个版本?VS2015 / MSVC 19支持constexpr函数。 - dyp
@dyp clang -fms-extensions,尽管结果应该能在没有constexpr的情况下在MSVC中工作。 - kirbyfan64sos
在您的情况下,是否可以添加一个包含字符串的全局/静态本地变量的定义?类似于const char str[] = "abcd"; - 这可以用于将字符串传递给元函数;直接传递字符串字面值是不允许的。 - dyp
@dyp 那么我可以对它进行索引吗? - kirbyfan64sos
啊,我刚刚忘记了const对象在常量表达式中的限制:它们需要具有整数或枚举类型。而对于constexpr对象的限制则要宽松得多。 - dyp
显示剩余2条评论
2个回答

1
假设我们现在不考虑大小端问题,你可以使用一个 constexpr union,例如:
union dirty_hack {
    long l;
    char[4] chars;
};

如果我们需要考虑字节序,问题会变得更加复杂。此外,long 的大小可能是 8,而不是 4。
另一个想法是,如果 long 是32位的,那么在 C++11 中支持 char32_t char4b = U'\UAABBFFFF'。但是你需要找出从 A45A 的十六进制值)的映射。然后将 char4b 转换为 long

在编译时进行类型游戏很可能不起作用。在标准中,通过联合进行类型游戏在C++中是被禁止的,并且reinterpret_cast也被禁止在常量表达式中使用。 (为什么在编译时进行类型游戏被禁止有更根本的原因,但我经常忘记它...)请参见http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1188 - dyp
@dyp,你是对的,用C++可能不可行,也许只能使用C语言来完成那部分。 - CS Pei

1
如果您可以以C++11模式(或更高版本)进行编译,则可以在常量表达式时间内索引字符串字面值:
#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;

话虽如此,如果您被允许使用C++11模式,您也应该能够使用constexpr

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;

你甚至可以编写用户定义的字符串字面量:
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;

1
好的想法,但是OP在评论中说这必须在MSVC下运行,而且不能使用constexpr。不幸的是,VS2013将"abcd"[0]拒绝为常量表达式:( - dyp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接