C++ 十六进制字符到std::string的constexpr转换

C++ 十六进制字符到std::string的constexpr转换,c++,string,c++11,type-conversion,C++,String,C++11,Type Conversion,我有很多这样的字符串: "343536"_hex 我想将其转换为相应的字节字符串。我使用的是C++11,并定义了一个用户定义的字符串文本来将其转换为十六进制字符串。但是,我当前的转换不能作为constexpr进行评估,这正是我所寻求的。我特别想使用类似的东西,但作为constexpr: std::string operator "" _hex(const char *s, std::size_t slen ) { std::string str; str.reserve(sle

我有很多这样的字符串:

"343536"_hex
我想将其转换为相应的字节字符串。我使用的是C++11,并定义了一个用户定义的字符串文本来将其转换为十六进制字符串。但是,我当前的转换不能作为
constexpr
进行评估,这正是我所寻求的。我特别想使用类似的东西,但作为
constexpr

std::string operator "" _hex(const char *s, std::size_t slen )
{
    std::string str;
    str.reserve(slen);
    char ch[3];
    unsigned long num;
    ch[2] = '\0';

    for ( ; slen; slen -= 2, s += 2) {
        ch[0] = s[0];
        ch[1] = s[1];
        num = strtoul(ch, NULL, 16);
        str.push_back(num);
    }
    return str;
}
试驾 问题 非常非常清楚我要问的是:
如何编写这种类型的C++11字符串文字转换,这种转换可以在编译时作为
constexpr
进行评估?

为了实现您试图实现的目标,您需要一些编译时与
constexpr
兼容的
string
类。然而,并没有这样一个标准的东西。我可以看到一些接近它的东西:

  • ,但界面并不漂亮
  • ,它具有所需的接口,但缺少
    constexpr
    支持
  • ,这正是您想要的,但尚未实现。如果您有一些空闲时间,它可能可以在C++11中实现
为了简化所有这些,让我们使用一个过度简化的
string\u literal
类。请注意,上面描述的一些类的尾部有一个
\0
,更接近
std::string
,但我们不需要添加一个

template<std::size_t N>
struct string_literal
{
    char data[N];
};
您可以使用模板用户定义的文字(带有
char…
)来去除字符串文字,并具有更漂亮的文字(
1234\u hex
,而不是
“1234”\u hex
):

您可以添加更多检查,以确保始终有偶数个字符,或确保没有任何坏字符。我提供的代码使用了C++14标准库中的一些功能,但我确保只使用可以在需要时在C++11中轻松重新实现的功能。请注意,由于对
constexpr
函数的宽松限制,您可能可以使用C++14编写更具可读性的程序


是一个使用上述所有函数和类的C++14示例。我确保您的测试程序仍然有效(我只是用循环中的
scr.data
替换了
scr
,因为我们使用了Edulocrated
string\u literal
类)。

这不太有效
有点轻描淡写,您的
constepr
函数中的大多数类型都不是literal类型,它们不能在编译时使用。我对问题进行了编辑以使其更清楚。为了记录在案,是的,我知道这种转换不能作为
constexpr
——这是问题的本质。
65
34
67
74
00
35
template<std::size_t N>
struct string_literal
{
    char data[N];
};
template<std::size_t N1, std::size_t N2, std::size_t... Ind1, std::size_t... Ind2>
constexpr auto concatenate(string_literal<N1> lhs, string_literal<N2> rhs,
                   std::index_sequence<Ind1...>, std::index_sequence<Ind2...>)
    -> string_literal<N1+N2>
{
    return { lhs.data[Ind1]... , rhs.data[Ind2]... };
}

template<std::size_t N1, std::size_t N2>
constexpr auto operator+(string_literal<N1> lhs, string_literal<N2> rhs)
    -> string_literal<N1+N2>
{
    using Indices1 = std::make_index_sequence<N1>;
    using Indices2 = std::make_index_sequence<N2>;
    return concatenate(lhs, rhs, Indices1{}, Indices2{});
}
template<char... Chars>
auto operator "" _hex()
    -> string_literal<sizeof...(Chars)/2>
{
    return process<Chars...>();
}
template<char C1, char C2>
constexpr auto process()
    -> string_literal<1>
{
    return { 16 * (C1 - '0') + (C2 - '0') };
}

template<char C1, char C2, char... Rest,
         typename = std::enable_if_t< (sizeof...(Rest) > 0), void >>
constexpr auto process()
    -> string_literal<sizeof...(Rest)/2 + 1>
{
    return process<C1, C2>() + process<Rest...>();
}