C++11 用户定义字面量

本文深入探讨了C++中的用户定义字面量概念,包括如何通过定义后缀创建自定义类型的字面量,字面量运算符的实现方式,以及字面量运算符允许的参数类型。同时,文章还介绍了字面量运算符重载时的调用优先级规则,并提供了多个测试示例。

一 用户定义字面量

定义:

通过定义用户定义的后缀,允许整数、浮点数、字符及字符串字面量产生用户定义类型的对象。

语法:

十进制字面量 ud-后缀  (1)
八进制字面量 ud-后缀  (2)
十六进制字面量 ud-后缀 (3)
二进制字面量 ud-后缀  (4)
分数常量 指数部分(可选) ud-后缀 (5)
数字序列 指数部分 ud-后缀 (6)
字符字面量 ud-后缀 (7)
字符串字面量 ud-后缀  (8)

注意:ud-后缀 必须以_开头

二 字面量运算符

即要实现用户定义字面量所要实现的函数。

格式:

operator "" 标识符
operator 用户定义字符串字面量 (C++14 起)

 第二种形式:用户定义字符串字面量:字符序列 "" 后不带空格,后随将作为ud-后缀的字符序列。这种特殊语法使得将语言关键词和保留标识符用作 ud-后缀 成为可能。例如允许下划线后随大写字母的用法(其他情况下这是保留标识符)(测试时第一种形式中下划线后随大写字母没有报错。)

三 字面量运算符允许的形参列表

( const char * )  (1)
( unsigned long long int )  (2)
( long double ) (3)
( char )  (4)
( wchar_t ) (5)
( char8_t ) (6) (C++20 起)
( char16_t )  (7)
( char32_t )  (8)
( const char * , std::size_t )  (9)
( const wchar_t * , std::size_t ) (10)
( const char8_t * , std::size_t ) (11)  (C++20 起)
( const char16_t * , std::size_t )  (12)
( const char32_t * , std::size_t )  (13)

注意:

1 不允许默认实参,不允许C语言连接

2 若字面量运算符是模板,则它必须有空形参列表,而且只能有一个模板形参,模板形参必须是元素类型为 char 的非类型模板形参包(该情况下称之为数值字面量运算符模板)或类类型的非类型模板形参(该情况下称之为字符串字面量运算符模板, C++20起)

数值字面量运算符模板举例:

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

字符串字面量运算符模板举例:略,不展开。

3 字面量运算符和字面量运算符模板都是普通的函数(和函数模板),它们可声明为 inline 或 constexpr,它们可拥有内部或外部连接,它们可显式调用,可取其地址等等。

四 字面量运算符有重载时用户定义字面量调用的优先级

1 对于用户定义整数字面量
若字面量运算符有重载,优先形参类型 unsigned long long 的字面量运算符,即调用

operator "" X(nULL)  // n 为去掉后缀的整数

否则调用原始字面量运算符或数值字面量运算符模板。(二者在同一个作用域只能存在一个,否则调用会有二义性)。

2 对于用户定义浮点字面量
若字面量运算符有重载,优先形参类型 long double 的字面量运算符,否则调用原始字面量运算符或数值字面量运算符模板。

3 对于用户定义字符串字面量
若重载集包含带非类型模板形参的字符串字面量运算符模板,且 str 对它是良构的模板实参,则用户定义字面量表达式被当作函数调用

operator "" X<str>() (C++20 起) // str为去掉后缀的字符串字面量

否则,用户定义字面量表达式被当做函数调用 operator "" X (str, len),其中 len 是字符串字面量的长度,不包含终止空字符。

4 对于用户定义字符字面量

调用

operator "" X (ch) // ch为去掉后缀的字符字面量

五 测试

#include <iostream>
#include <string>

namespace demo1 {
void operator "" _a(const char* s) {
  std::cout << "operator \"\"_a(const char* s)  " << s << std::endl;
}
}

namespace demo2 {
template <char... args>
void operator "" _a() {
  std::cout << "template  " << sizeof...(args) << std::endl;
}
}

namespace demo3 {
void operator "" _a(const char* s) {
  std::cout << "operator \"\"_a(const char* s)" << std::endl;
}
void operator ""_a(unsigned long long i) {
  std::cout << "operator \"\"_a(unsigned long long i)" << std::endl;
}
}

namespace demo4 {
void operator "" _a(const char* s) {
  std::cout << "operator \"\"_a(const char* s)" << std::endl;
}
void operator ""_a(long double f) {
  std::cout << "operator \"\"_a(long double f)" << std::endl;
}
}

namespace demo5 {
void operator "" _a(const char* s) {
  std::cout << "operator \"\"_a(const char* s)" << std::endl;
}
void operator "" _a(const char* s, size_t) {
  std::cout << "operator \"\"_a(const char* s, size_t)" << std::endl;
}
void operator "" _a(const char16_t* s, size_t) {
  std::cout << "operator \"\"_a(const char16_t* s, size_t)" << std::endl;
}
void operator "" _a(const char32_t* s, size_t) {
  std::cout << "operator \"\"_a(const char32_t* s, size_t)" << std::endl;
}
}

namespace demo6 {
void operator ""  _A(const char32_t* s, size_t) {} // 未报错
void operator ""_A(const char* s) {
  std::cout << "operator \"\"_A(const char* s)" << std::endl;
}
}

int main() {
  {
    using namespace demo1;
    123_a;
  }
  {
    using namespace demo2;
    123_a;
  }
  {
    using namespace demo3;
    123_a;
  }
  {
    using namespace demo4;
    123_a;
    1.2_a;
  }
  {
    using namespace demo5;
    u8"123"_a;
    u"123"_a;
  }
  {
    using namespace demo6;
    123_A;
  }
  std::cin.get();
  return 0;
}

六 注意

在表达式中使用用户定义字面量时注意用括号、空格等分隔开 。

七 参考

用户定义字面量

### 用户自定义字面量的定义方式 在C++中,用户可以通过定义**字面量运算符函数(Literal Operator Function)**来创建自己的字面量。这些函数以 `operator""` 开头,并通过后缀标识符区分不同的自定义类型。例如,可以为表示长度、时间或单位的数值定义特定的后缀,使代码更具可读性。 #### 自定义字面量的基本语法 自定义字面量的函数形式如下: ```cpp ReturnType operator"" _suffix(ParameterType literal); ``` 其中 `_suffix` 是一个合法的后缀名称,通常以 `_` 开头以避免与标准库冲突;`ParameterType` 可以是以下几种之一: - `unsigned long long`(用于整数字面量) - `long double`(用于浮点数字面量) - `const char*`(用于字符串字面量) - `const char*, std::size_t`(用于原始字符数组) #### 示例:自定义单位转换 以下是一个示例,展示如何定义一个表示米(meters)和千克(kilograms)的自定义字面量: ```cpp #include <iostream> // 自定义字面量:米 long double operator"" _m(long double meters) { return meters; } // 自定义字面量:千克 long double operator"" _kg(long double kg) { return kg; } int main() { long double length = 10.5_m; // 使用自定义字面量表示米 long double weight = 75.3_kg; // 使用自定义字面量表示千克 std::cout << "Length: " << length << " m" << std::endl; std::cout << "Weight: " << weight << " kg" << std::endl; return 0; } ``` 此代码中,`_m` 和 `_kg` 是用户定义后缀,它们将输入的数值直接返回为相应的物理量单位,提升了代码的语义清晰度[^2]。 #### 示例:字符串拼接 除了数值型字面量,还可以为字符串定义自定义字面量。例如,在 C++14 中,`std::string` 提供了 `"..."s` 的形式用于创建 `std::string` 类型的对象: ```cpp #include <iostream> #include <string> int main() { using namespace std::literals::string_literals; std::string greeting = "Hello, "s + "World!"s; // 使用字符串字面量拼接 std::cout << greeting << std::endl; return 0; } ``` 这种形式使得字符串操作更加直观,尤其在进行多次拼接时更显优势[^1]。 #### 注意事项 - 所有自定义字面量后缀应以 `_` 开头,以避免与未来标准版本中的新特性冲突。 - 不要使用与现有标准字面量相同的后缀,如 `UL` 或 `F`,这可能导致编译器警告或歧义。 - 需要包含适当的头文件并启用 C++11 或更高版本支持,否则可能无法识别某些特性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值