7

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

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
}

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

4

5 回答 5

7

这是我在回答我自己的问题时的看法:使用作为 aconstexpr与字符串文字一起实现的用户定义文字允许有效地为相关值指定解析器!有两个部分有点难看:

  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';
}
于 2013-09-23T05:40:48.560 回答
5

从 C++14 开始,这是有效的:

use_mask<0b1001'0010'1001'0010> its_just_what_i_wanted;
于 2014-06-27T19:01:43.907 回答
1

不完美,因为它需要每个二进制数字之间的逗号,但允许任何数量的空格和任何二进制数字的任何 const expr - 例如 0xFFFF FFFF FFFF FFFF 应该是:

use_mask<bit64<
 1,1,1,1,  1,1,1,1,  1,1,1,1,  1,1,1,1,
 1,1,1,1,  1,1,1,1,  1,1,1,1,  1,1,1,1,
 1,1,1,1,  1,1,1,1,  1,1,1,1,  1,1,1,1,
 1,1,1,1,  1,1,1,1,  1,1,1,1,  1,1,1,1
>::VAL>

代码:

template <
    bool b3F,bool b3E,bool b3D,bool b3C,bool b3B,bool b3A,bool b39,bool b38,
    bool b37,bool b36,bool b35,bool b34,bool b33,bool b32,bool b31,bool b30,
    bool b2F,bool b2E,bool b2D,bool b2C,bool b2B,bool b2A,bool b29,bool b28,
    bool b27,bool b26,bool b25,bool b24,bool b23,bool b22,bool b21,bool b20,
    bool b1F,bool b1E,bool b1D,bool b1C,bool b1B,bool b1A,bool b19,bool b18,
    bool b17,bool b16,bool b15,bool b14,bool b13,bool b12,bool b11,bool b10,
    bool b0F,bool b0E,bool b0D,bool b0C,bool b0B,bool b0A,bool b09,bool b08,
    bool b07,bool b06,bool b05,bool b04,bool b03,bool b02,bool b01,bool b00
>
class bit64
{
public:
    static const unsigned long long VAL=0UL
        |((unsigned long long)b00<< 0)|((unsigned long long)b01<< 1)|((unsigned long long)b02<< 2)|((unsigned long long)b03<< 3)
        |((unsigned long long)b04<< 4)|((unsigned long long)b05<< 5)|((unsigned long long)b06<< 6)|((unsigned long long)b07<< 7)
        |((unsigned long long)b08<< 8)|((unsigned long long)b09<< 9)|((unsigned long long)b0A<<10)|((unsigned long long)b0B<<11)
        |((unsigned long long)b0C<<12)|((unsigned long long)b0D<<13)|((unsigned long long)b0E<<14)|((unsigned long long)b0F<<15)
        |((unsigned long long)b10<<16)|((unsigned long long)b11<<17)|((unsigned long long)b12<<18)|((unsigned long long)b13<<19)
        |((unsigned long long)b14<<20)|((unsigned long long)b15<<21)|((unsigned long long)b16<<22)|((unsigned long long)b17<<23)
        |((unsigned long long)b18<<24)|((unsigned long long)b19<<25)|((unsigned long long)b1A<<26)|((unsigned long long)b1B<<27)
        |((unsigned long long)b1C<<28)|((unsigned long long)b1D<<29)|((unsigned long long)b1E<<30)|((unsigned long long)b2F<<31)
        |((unsigned long long)b20<<32)|((unsigned long long)b21<<33)|((unsigned long long)b22<<34)|((unsigned long long)b23<<35)
        |((unsigned long long)b24<<36)|((unsigned long long)b25<<37)|((unsigned long long)b26<<38)|((unsigned long long)b27<<39)
        |((unsigned long long)b28<<40)|((unsigned long long)b29<<41)|((unsigned long long)b2A<<42)|((unsigned long long)b2B<<43)
        |((unsigned long long)b2C<<44)|((unsigned long long)b2D<<45)|((unsigned long long)b2E<<46)|((unsigned long long)b3F<<47)
        |((unsigned long long)b30<<48)|((unsigned long long)b31<<49)|((unsigned long long)b32<<50)|((unsigned long long)b33<<51)
        |((unsigned long long)b34<<52)|((unsigned long long)b35<<53)|((unsigned long long)b36<<54)|((unsigned long long)b37<<55)
        |((unsigned long long)b38<<56)|((unsigned long long)b39<<57)|((unsigned long long)b3A<<58)|((unsigned long long)b3B<<59)
        |((unsigned long long)b3C<<60)|((unsigned long long)b3D<<61)|((unsigned long long)b3E<<62)|((unsigned long long)b3F<<63)
        ;
};

对于支持它的编译器,这也可能是 constexpr

于 2013-11-07T03:02:31.490 回答
0

我这里没有 C++ 编译器来进行实验,但您可以尝试以下方法(使用 UDL 的模板形式):

template<char... chars>
constexpr unsigned long long operator"" _bin();

template<char... chars>
constexpr unsigned long long operator"" _bin<'0', chars...>() {
  // return correctly shifted calculated value.
}

template<char... chars>
constexpr unsigned long long operator"" _bin<'1', chars...>() {
  // return correctly shifted calculated value.
}

template<char... chars>
constexpr unsigned long long operator"" _bin<'_', chars...>() {
  // simply forward to rest
}

抱歉不够具体,我这里没有工具,但我看到 UDL 解析是这样完成的。

于 2013-09-24T06:34:43.707 回答
0

另一种方法是使用宏:

#define ULongLongHex(p1, p2, p3, p4) (0x ## p1 ## p2 ## p3 ## p4)

ULongLongHex(0123,4567,89ab,cdef)

但没有检查。:(

于 2013-09-23T11:14:47.297 回答