自定义字面量

Forums: 

img: 

字面量 literal 就是诸如 1234 、 0xfe、 3.14 、 2.71828f、 "hello,world"、 'x' 这样的量,这些都是对应类型的书写常量。 在数学或是物理中, 除了整数和浮点数表示外, me 们还常见诸如 1+2i 、32 kg 这样的表示,学汇编的恐怕还熟悉 10110011b 这样的表示(二进制形式)。 本来 c++ 从 c 那里只继承了一些基本类型的一些固有的表示方法,不过 c++11 对于这种功能进行了扩展,也就是 me 们可以自定义一些数据表示形式,比如 1+2i 表示复数, 1011b 是整数的二进制表示。

c++ 的这种扩展是通过运算符 "" 的重载实现的。下面是一个复数 a+bi 表示的程序 demo :

  1. #include <iostream>
  2. #include <complex>
  3.  
  4. constexpr std::complex<long double> operator"" i(long double d)
  5. {
  6.     return {0.0, d};
  7. }
  8.  
  9. int  main()
  10. {
  11.     std::complex<long double> z = 3.0L + 6.0i;
  12.     z /= 3;
  13.     std::cout << z << std::endl;    // (1,2)
  14.    
  15.     return 0;
  16. }

有好几点值得说明:

  1. i 这种直接作为后缀的表示形式 c++11 标准不提倡, 提倡用户使用 _ 打头的后缀, 诸如 1+2_i 的形式;
  2. 运算符 "" 重载函数的参数类型,比如上面的是 long double, 不是随意的, 也就是标准指定了若干种类型, 对于 double 就是不行的;
  3. 3.0L + 6.0i 中的 3.0 后的 L 表明 3.0 是一个 long double 类型, 按理说这里的 L 是多余的, 但是 me 使用的 gcc 版本如果省去了 L 就是错误; 后面的 z /= 3; 却又不要求写成 3.0L ;更奇怪的是 z = z / 3; 是错误的, 而 z /= 3; 确实正确的;

前面是一个复数a+bi表示的例子,这里的是一个二进制表示整数的例子,也就是说 1000_b 表示整数 8, 10000000_B 表示整数 128 。 一种实现方法如下:(me google 的一个方法,非 me 原创, me 只是做了简单修改)

  1. #include <iostream>
  2.  
  3. template<char Head, char... Tail>
  4. struct binary    // 一般的转换方法
  5. {
  6.     static_assert(Head == '0' || Head == '1', "invalid binary digit" ) ;
  7.     static const unsigned long long value = ((Head - '0') << sizeof...(Tail)) + binary<Tail...>::value;
  8. };
  9.  
  10. template<>
  11. struct binary<'0'>    // 0 的转换
  12. {
  13.     static const unsigned long long value = 0;
  14. };
  15.  
  16. template<>
  17. struct binary<'1'>    // 1 的转换
  18. {
  19.     static const unsigned long long value = 1;
  20. };
  21.  
  22. template<char... BinaryLiteral>
  23. constexpr unsigned long long operator "" _b()    // _b 后缀的字面量重载
  24. {
  25.     return binary<BinaryLiteral...>::value;
  26. }
  27.  
  28. template<char... BinaryLiteral>
  29. constexpr unsigned long long operator "" _B()    // _B 后缀的字面量重载
  30. {
  31.     return binary<BinaryLiteral...>::value;
  32. }
  33.  
  34. int main()
  35. {
  36.     std::cout << 1011011100011_b  << ' ' << 10001000_B << std::endl;    // 5859 136
  37. }
    说明:
  1. 这里使用了带可变参数的模版;而且可以使用 sizeof 来求参数的个数(这种使用方法 me 是第一次见,O__O"…);
  2. 这里还使用了模板元编程的技术,是一种编译期求值的技术;
  3. 总之,这里的程序碉堡了,O__O"…

精诚所至,金石为开