本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成,引用內(nèi)容的版權(quán)歸原始作者所有,僅限于學習研究使用,不得用于任何商業(yè)用途。
用戶定義數(shù)據(jù)標識(User-defined literals)
C++提供了許多內(nèi)建數(shù)據(jù)類型的數(shù)據(jù)標識(2.14節(jié)變量):
123 // int整型
1.2 // double雙精度型
1.2F // float浮點型
’a' // char字符型
1ULL // unsigned long long64位無符號長整型
0xD0 // hexadecimal unsigned十六進制無符號整型
"as" // string字符串
但是在C++98中并沒有為用戶自定義的變量類型提供數(shù)據(jù)標識。這就違反甚至沖突于“用戶自定類型應該和內(nèi)建類型一樣得到支持”的原則。在特殊情況下,人們有以下的需求:
"Hi!"s //字符串,不是“以零字符為終結(jié)的字符數(shù)組”
1.2i //虛數(shù)
123.4567891234df //十進制浮點型(IBM)
101010111000101b //二進制
123s //秒
123.56km //不是英里(單位)
1234567890123456789012345678901234567890x //擴展精度
C++11通過在變量后面加上一個后綴來標定所需的類型以支持“用戶定義數(shù)據(jù)標識”,自字義后綴用operator""定義,就是一種特殊的函數(shù)。后綴名必須以下劃線開頭,因為沒有下劃線的后綴是留給std用的。后綴的參數(shù)只能是unsigned long long、long double、const char或者const char + size_t。沒了,它就是這么簡單易上手又很實用的特性。一般來說適合編為后綴的是單位,如kg,km。例如:
constexpr complex operator "" i(long double d) // 設計中的數(shù)據(jù)標識
{
return {0,d}; //complex是一個數(shù)據(jù)標識
}
// 將n個字符構(gòu)造成字符串std::string對象的數(shù)據(jù)標識
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; // 復數(shù)complex(2,1)
基本(實現(xiàn))方法是編譯器在解析什么語句代表一個變量之后,再分析一下后綴。用戶自定義數(shù)據(jù)標識機制只是簡簡單單的允許用戶制定一個新的后綴,并決定如何對它之前的數(shù)據(jù)進行處理。要想重新定義一個內(nèi)建的數(shù)據(jù)標識的意義或者它的參數(shù)、語法是不可能的。一個數(shù)據(jù)標識操作符可以使用它(前面)的數(shù)據(jù)標識傳遞過來的處理過的值(如果是使用新的沒有定義過的后綴的值)或者沒有處理過的值(作為一個字符串)。
要得到一個沒有處理過的字符串,只要使用一個單獨的const char*參數(shù)即可,例如:
Bignum operator"" x(const char* p)
{
return Bignum(p);
}
void f(Bignum);
f(1234567890123456789012345678901234567890x);
這個C語言風格的字符串”1234567890123456789012345678901234567890″被傳遞給了操作符 operator”” x()。注意,我們并沒有明確地把數(shù)字轉(zhuǎn)換成字符串。
有以下四種數(shù)據(jù)標識的情況,可以被用戶定義后綴來使用用戶自定義數(shù)據(jù)標識:
- 整型標識:允許傳入一個unsigned long long或者const char*參數(shù)
- 浮點型標識:允許傳入一個long double或者const char*參數(shù)
- 字符串標識:允許傳入一組(const char*,size_t)參數(shù)
- 字符標識:允許傳入一個char參數(shù)。
根據(jù) C++ 11 標準,只有下面這些簽名是合法的:
char const*
unsigned long long
long double
char const, std::size_t
wchar_t const*, std::size_t
char16_t const*, std::size_t
char32_t const*, std::size_t
上面列出的第一個簽名不要同字符串相混淆,應該被稱為原始字面量 raw literal 操作符。例如:
char const* operator"" _r(char const* s)
{
return s;
}
int main()
{
std::cout << 12_r << '\n';
}
注意,你為字符串標識定義的標識操作符不能只帶有一個const char*參數(shù)(而沒有大小)。例如:
//警告,這個標識操作符并不能像預想的那樣子工作
string operator"" S(const char* p);
"one two"S; //錯誤,沒有適用的標識操作符
根本原因是如果我們想有一個“不同的字符串”,我們同時也想知道字符的個數(shù)。后綴可能比較短(例如,s是字符串的后綴,i是虛數(shù)的后綴,m是米的后綴,x是擴展類型的后綴),所以不同的用法很容易產(chǎn)生沖突,我們可以使用namespace(命名空間)來避免這些名字沖突:
namespace Numerics {
// …
class Bignum { /* … */ };
namespace literals {
operator"" X(char const*);
}
}
using namespace Numerics::literals;
參考資料
C++11 用戶自定義字面值
C++11 新特性:用戶定義字面量
【c++11FAQ】用戶定義數(shù)據(jù)標識
cpp11新特性詳解與應用