constexpr将十六进制字符转换为std :: string

Edw*_*ard 6 c++ string type-conversion c++11

我有很多像这样的字符串:

"343536"_hex
Run Code Online (Sandbox Code Playgroud)

我想将其转换为相应的字节字符串.我正在使用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;
}
Run Code Online (Sandbox Code Playgroud)

测试司机

int main()
{
    std::string src{"653467740035"_hex};
    for (const auto &ch : src)
        std::cout << std::hex << std::setw(2) << std::setfill('0') 
                  << (unsigned)ch << '\n';
}
Run Code Online (Sandbox Code Playgroud)

样本输出

65
34
67
74
00
35
Run Code Online (Sandbox Code Playgroud)

这个问题

非常非常清楚我要问的是这样的: 我怎样才能编写这种类型的C++ 11字符串文字转换,可以在编译时作为一个constexpr

Mor*_*enn 10

为了实现您要执行的操作,您需要具有一些string兼容的编译时类constexpr.虽然没有这样的标准.我可以看到一些接近它的东西:

为了简化所有这些,让我们使用一个过于简化的string_literal类.请注意,上面描述的某些类的尾部\0更接近std::string,但我们不打算添加一个.

template<std::size_t N>
struct string_literal
{
    char data[N];
};
Run Code Online (Sandbox Code Playgroud)

我们还将提供operator+连接.需要一些时间来解释它是如何工作的,并且它与问题并不真正相关.假设它只是一些模板魔法(std::integer_sequence是C++ 14实用程序,但可以在C++ 11中实现):

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{});
}
Run Code Online (Sandbox Code Playgroud)

您可以使用模板用户定义的文字(with char...)来删除字符串文字并具有更漂亮的文字(1234_hex而不是"1234"_hex):

template<char... Chars>
auto operator "" _hex()
    -> string_literal<sizeof...(Chars)/2>
{
    return process<Chars...>();
}
Run Code Online (Sandbox Code Playgroud)

现在,您只需要一个可以成对处理角色的功能.通用的和"完成"条件的重载.请注意,enable_if_t需要避免模糊的函数调用(这是C++ 14,但您可以typename std::enable_if<...>::type在C++ 11中替换它).将字符转换为等效数字的"真实"工作是在process只有两个模板参数的重载中完成的.

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...>();
}
Run Code Online (Sandbox Code Playgroud)

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

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