C++11 字面量操作符

在 C++ 11 中,引入了字面量操作符(literal operator),使用的方法就像下面这样:

long double operator "" _w(long double);
std::string operator "" _w(const char16_t*, size_t);
unsigned operator "" _w(const char*);
int main() {
    1.2_w; // calls operator "" _w(1.2L)
    u"one"_w; // calls operator "" _w(u"one", 3)
    12_w; // calls operator "" _w("12")
    "two"_w; // error: no applicable literal operator
}

这个操作符也可以声明为模板函数,如果声明为了模板函数,参数列表必须为空,而且模板参数列表只能有一个参数——用来获取每一个字符的变长列表:

template <char...> double operator "" _x();

通常情况下,这个也可以叫做数值字面量操作符。

有了这个操作符的帮助,可以做一些编译期的运算:

// convert single char to corresponding int value at compile time:
constexpr int toInt(char c) {
  // hexadecimal letters:
  if (c >= 'A' && c <= 'F') {
    return static_cast<int>(c) - static_cast<int>('A') + 10;
  }
  if (c >= 'a' && c <= 'f') {
    return static_cast<int>(c) - static_cast<int>('a') + 10;
  }
  // other (disable '.' for floating-point literals):
  assert(c >= '0' && c <= '9');
  return static_cast<int>(c) - static_cast<int>('0');
}

// parse array of chars to corresponding int value at compile time:
template<std::size_t N>
constexpr int parseInt(char const (&arr)[N]) {
  int base = 10;       // to handle base (default: decimal)
  int offset = 0;      // to skip prefixes like 0x
  if (N > 2 && arr[0] == '0') {
    switch (arr[1]) {
      case 'x':        // prefix 0x or 0X, so hexadecimal
      case 'X':
        base = 16;
        offset = 2;
        break;
      case 'b':        // prefix 0b or 0B (since C++14), so binary
      case 'B':
        base = 2;
        offset = 2;
        break;
      default:         // prefix 0, so octal
        base = 8;
        offset = 1;
        break;
    }
  }
  // iterate over all digits and compute resulting value:
  int value = 0;
  int multiplier = 1;
  for (std::size_t i = 0; i < N - offset; ++i) {
    if (arr[N-1-i] != '\'') { // ignore separating single quotes (e.g. in 1'000)
      value += toInt(arr[N-1-i]) * multiplier;
      multiplier *= base;
    }
  }
  return value;
}

template<typename T, T Value>
struct CTValue
{ 
  static constexpr T value = Value;
};

// literal operator: parse integral literals with suffix _c as sequence of chars:
template<char... cs>
constexpr auto operator"" _c() {
  return CTValue<int, parseInt<sizeof...(cs)>({cs...})>{};
}