# 用戶定義數據標識(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