# 用户定义数据标识(User-defined literals)
C++提供了许多内建数据类型的数据标识(2.14节变量):
```
123 // int整型
1.2 // double双精度型
1.2F // float浮点型
’a' // char字符型
1ULL // unsigned long long64位无符号长整型
0xD0 // hexadecimal unsigned十六进制无符号整型
"as" // string字符串
```
但是在C++98中并没有为用户自定义的变量类型提供数据标识。这就违反甚至冲突于“用户自定类型应该和内建类型一样得到支持”的原则。在特殊情况下,人们有以下的需求:
```
"Hi!"s //字符串,不是“以零字符为终结的字符数组”
1.2i //虚数
123.4567891234df //十进制浮点型(IBM)
101010111000101b //二进制
123s //秒
123.56km //不是英里(单位)
1234567890123456789012345678901234567890x //扩展精度
```
C++11通过在变量后面加上一个后缀来标定所需的类型以支持“用户定义数据标识”,例如:
```
constexpr complex operator "" i(long double d) // 设计中的数据标识
{
return {0,d}; //complex是一个数据标识
}
// 将n个字符构造成字符串std::string对象的数据标识
std::string operator""s (const char* p, size_t n)
{
return string(p,n); // 需要释放存储空间
}
```
这里需要注意的是,constexpr的使用可以进行编译时期的计算。使用这一功能,我们可以这样写:
```
template <class T> void f(const T&);
f("Hello"); // 传递char*指针给f()
f("Hello"s); // 传递(5个字符的)字符串对象给f()
f("Hello n"s); // 传递(6个字符的)字符串对象给f()
auto z = 2+1i; // 复数complex(2,1)
```
基本(实现)方法是编译器在解析什么语句代表一个变量之后,再分析一下后缀。用户自定义数据标识机制只是简简单单的允许用户制定一个新的后缀,并决定如何对它之前的数据进行处理。要想重新定义一个内建的数据标识的意义或者它的参数、语法是不可能的。一个数据标识操作符可以使用它(前面)的数据标识传递过来的处理过的值(如果是使用新的没有定义过的后缀的值)或者没有处理过的值(作为一个字符串)。
要得到一个没有处理过的字符串,只要使用一个单独的const char*参数即可,例如:
```
Bignum operator"" x(const char* p)
{
return Bignum(p);
}
void f(Bignum);
f(1234567890123456789012345678901234567890x);
```
这个C语言风格的字符串”1234567890123456789012345678901234567890″被传递给了操作符 operator”” x()。注意,我们并没有明确地把数字转换成字符串。
有以下四种数据标识的情况,可以被用户定义后缀来使用用户自定义数据标识:
* 整型标识:允许传入一个unsigned long long或者const char*参数
* 浮点型标识:允许传入一个long double或者const char*参数
* 字符串标识:允许传入一组(const char*,size_t)参数
* 字符标识:允许传入一个char参数。
注意,你为字符串标识定义的标识操作符不能只带有一个const char*参数(而没有大小)。例如:
```
//警告,这个标识操作符并不能像预想的那样子工作
string operator"" S(const char* p);
"one two"S; //错误,没有适用的标识操作符
```
根本原因是如果我们想有一个“不同的字符串”,我们同时也想知道字符的个数。后缀可能比较短(例如,s是字符串的后缀,i是虚数的后缀,m是米的后缀,x是扩展类型的后缀),所以不同的用法很容易产生冲突,我们可以使用namespace(命名空间)来避免这些名字冲突:
```
namespace Numerics {
// …
class Bignum { /* … */ };
namespace literals {
operator"" X(char const*);
}
}
using namespace Numerics::literals;
```
参考:
* Standard 2.14.8 User-defined literals
* [N2378==07-0238] Ian McIntosh, Michael Wong, Raymond Mak, Robert Klarer, Jens Mauer, Alisdair Meredith, Bjarne Stroustrup, David Vandevoorde:
[User-defined Literals (aka. Extensible Literals (revision 3))](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2378.pdf).
- C++11 FAQ中文版 - C++11 FAQ
- Stroustrup先生关于中文版的授权许可邮件
- Stroustrup先生关于C++11 FAQ的一些说明
- 关于C++11的一般性的问题
- 您是如何看待C++11的?
- 什么时候C++0x会成为一部正式的标准呢?
- 编译器何时将会实现C++11标准呢?
- 我们何时可以用到新的标准库文件?
- C++0x将提供何种新的语言特性呢?
- C++11会提供哪些新的标准库文件呢?
- C++0x努力要达到的目标有哪些?
- 指导标准委员会的具体设计目标是什么?
- 在哪里可以找到标准委员会的报告?
- 从哪里可以获得有关C++11的学术性和技术性的参考资料?
- 还有哪些地方我可以读到关于 C++0x的资料?
- 有关于C++11的视频吗?
- C++0x难学吗?
- 标准委员会是如何运行的?
- 谁在标准委员会里?
- 实现者应以什么顺序提供C++11特性?
- 将会是C++1x吗?
- 标准中的"concepts"怎么了?
- 有你不喜欢的C++特性吗?
- 关于独立的语言特性的问题
- __cplusplus宏
- alignment(对齐方式)
- 属性(Attributes)
- atomic_operations
- auto – 从初始化中推断数据类型
- C99功能特性
- 枚举类——具有类域和强类型的枚举
- carries_dependency
- 复制和重新抛出异常
- 常量表达式(constexpr)
- decltype – 推断表达式的数据类型
- 控制默认函数——默认或者禁用
- 控制默认函数——移动(move)或者复制(copy)
- 委托构造函数(Delegating constructors)
- 并发性动态初始化和析构
- noexcept – 阻止异常的传播与扩散
- 显式转换操作符
- 扩展整型
- 外部模板声明
- 序列for循环语句
- 返回值类型后置语法
- 类成员的内部初始化
- 继承的构造函数
- 初始化列表
- 内联命名空间
- Lambda表达式
- 用作模板参数的局部类型
- long long(长长整数类型)
- 内存模型
- 预防窄转换
- nullptr——空指针标识
- 对重载(override)的控制: override
- 对重载(override)的控制:final
- POD
- 原生字符串标识
- 右角括号
- 右值引用
- Simple SFINAE rule
- 静态(编译期)断言 — static_assert
- 模板别名(正式的名称为"template typedef")
- 线程本地化存储 (thread_local)
- unicode字符
- 统一初始化的语法和语义
- (广义的)联合体
- 用户定义数据标识(User-defined literals)
- 可变参数模板(Variadic Templates)
- 关于标准库的问题
- abandoning_a_process
- 算法方面的改进
- array
- async()
- atomic_operations
- 条件变量(Condition variables)
- 标准库中容器方面的改进
- std::function 和 std::bind
- std::forward_list
- std::future和std::promise
- 垃圾回收(应用程序二进制接口)
- 无序容器(unordered containers)
- 锁(locks)
- metaprogramming(元编程)and type traits
- 互斥
- 随机数的产生
- 正则表达式(regular expressions)
- 具有作用域的内存分配器
- 共享资源的智能指针——shared_ptr
- smart pointers
- 线程(thread)
- 时间工具程序
- 标准库中的元组(std::tuple)
- unique_ptr
- weak_ptr
- system error