c++ - 如何为非类型模板参数使用数字分隔符?

标签 c++ c++11 literals

我有一个模板,它采用 unsigned long long 类型的非类型模板参数。实例化此模板很快就会变得困惑,因为它涉及太多数字。事实上,理想情况下,我会使用二进制表示,使情况更糟:最多有 64 个 01 字符。我怎样才能创建一个视觉上可识别的论点。例如:

template <unsigned long long>
struct use_mask {
    // for this question it doesn't matter what the template actually does
};

int main() {
    use_mask<0b1001001010010010>    unreadable;    // OK, there are no binary literals
    use_mask<0b1001,0010,1001,0010> more_readable; // ... nor are there digit separators
}

有没有办法近似后一种表示法,可能在值前后有一些东西?

最佳答案

以下是我对自己问题的回答:使用作为 constexpr 实现的用户定义文字和字符串文字可以有效地为相关值指定解析器!有两部分略显丑陋:

  1. 实际文字用双引号括起来。
  2. 在所述字符串的末尾有一个用户定义的文字。

除此之外,这种方法实际上允许指定整数文字,包括数字分隔符。我目前还不能创建一个精美的版本来验证分隔符是否位于正确的位置,但这应该只是正确编程的一个小细节。下面是一个实现相应用户定义文字的程序,它允许像这样使用

use_mask<"0b0101,0101,0101,0101,0011,0101"_sep> um1;
use_mask<"0x0123,4567,89ab,cdef"_sep>           um2;

当然,这实际上也是在使用文字。实际文字是

"0b0101,0101,0101,0101,0011,0101"_sep
"0x0123,4567,89ab,cdef"_sep

...而且它们可以完全分开使用。抛出异常的错误消息不一定像我希望的那样漂亮。还指出,使用用户定义的文字来处理数字分隔符会排除使用其他用户定义的文字。

#include <algorithm>
#include <iostream>
#include <stdexcept>

template <unsigned long long Value>
struct use_mask {
    static constexpr unsigned long long value = Value;
};

// ------------------------------------------------------------------------

constexpr bool is_digit(char c, unsigned base)
{
    return '0' <= c && c < '0' + int(base < 10u? base: 10u);
}

constexpr bool is_hexdigit(char c)
{
    return ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
}

constexpr unsigned long long hex_value(char c)
{
    return c - (('a' <= c && c <= 'f')? 'a': 'A') + 10;
}

// ------------------------------------------------------------------------

constexpr unsigned long long decode(unsigned long long value,
                                    unsigned base,
                                    char const* str, size_t n)
{
    return n == 0
        ? value
        : (str[0] == ','
           ? decode(value, base, str + 1, n - 1)
           : (is_digit(str[0], base)
              ? decode(value * base + str[0] - '0', base, str + 1, n - 1)
              : (base == 16u && is_hexdigit(str[0])
                 ? decode(value * base + hex_value(str[0]),
                          base, str + 1, n - 1)
                 : throw "ill-formed constant with digit separators"
                 )
              )
           );
}

constexpr unsigned long long operator"" _sep(char const* value,
                                             std::size_t n)
{
    return 2 < n && value[0] == '0'
        ? ((value[1] == 'b' || value[1] == 'B')
           ? decode(0ull, 2, value + 2, n - 2)
           : ((value[1] == 'x' || value[1] == 'X')
              ? decode(0ull, 16, value + 2, n - 2)
              : decode(0ull, 8, value + 1, n - 1)))
        : decode(0ull, 10, value, n);
}

int main()
{
    std::cout << use_mask<"0b1010,1010"_sep>::value << "\n";
    std::cout << use_mask<"02,52"_sep>::value << "\n";
    std::cout << use_mask<"1,70"_sep>::value << "\n";
    std::cout << use_mask<"0xA,A"_sep>::value << "\n";
#ifdef ERROR
    std::cout << use_mask<"0xx,A"_sep>::value << "\n";
#endif

    std::cout << use_mask<"0b0101,0101,0101,0101,0011,0101"_sep>::value
              << '\n';
    std::cout << use_mask<"0x0123,4567,89ab,cdef"_sep>::value << '\n';
}

关于c++ - 如何为非类型模板参数使用数字分隔符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18951658/

相关文章:

C++读取用户输入比较数组

c++ - 在方法中更改类的私有(private)值而不将更改返回给 main()

c++ - GNU g++ 4.9.2 中的重载 endl 编译问题

python - Django - 以 10 为基数的 int() 的无效文字 python django

c - C 字符串文字的结束十六进制指定部分

c++ - 与默认构造函数 : clang produces parse error while gcc did not 成为 friend

c++ - spirit SA属性编号

c++ - 打包 OpenCV Dll 以分发 C++ DLL

c++ - 如何将焦点返回到窗口?

c - long long 是 8 个字节,但我得到整数溢出?