C++11 用户定义字面量

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 用户定义字面量

定义:

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

语法:

十进制字面量 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++中的字面量概念及其使用方法 #### 什么是字面量? 在C++中,**字面量(Literal)** 是指直接出现在源代码中的常量值。它们可以是整数、浮点数、字符、字符串等类型。字面量的主要特点是它们可以直接被编译器识别并转换为相应的数据类型,而不需要额外的变量声明或初始化过程。 例如: - `42` 是一个整数字面量。 - `3.14` 是一个浮点数字面量。 - `'A'` 是一个字符字面量。 - `"Hello, World!"` 是一个字符串字面量。 从C++11开始,标准引入了**用户自定义字面量(User-defined Literals)**,允许开发者通过后缀的方式扩展已有的字面量类型,或者创建全新的字面量类型[^2]。这种机制使得代码更加简洁和直观。 #### 字面量的定义与使用方式 ##### 1. **基本字面量** 基本字面量的使用非常简单,直接将数值或字符串写入代码即可。例如: ```cpp int a = 42; // 整数字面量 double b = 3.14; // 浮点数字面量 char c = 'A'; // 字符字面量 const char* d = "Hello"; // 字符串字面量 ``` ##### 2. **用户自定义字面量** 用户自定义字面量是通过定义特定的运算符函数来实现的。这些运算符函数通常以 `_` 开头,以便区分标准库中的字面量。例如,C++14标准库中提供了时间相关的字面量,位于 `std::literals::chrono_literals` 命名空间下,用于简化时间单位的操作。 以下是一个简单的示例,展示如何定义一个表示米(meters)的自定义字面量: ```cpp #include <iostream> // 定义一个表示米的自定义字面量 long double operator"" _m(long double meters) { return meters; } int main() { long double distance = 5.5_m; // 使用自定义字面量 std::cout << "Distance: " << distance << " meters" << std::endl; return 0; } ``` 在这个例子中,`_m` 是一个自定义的后缀,表示输入的数值是以米为单位的距离。通过这种方式,代码变得更加直观和易读。 ##### 3. **标准库中的用户自定义字面量** C++14引入了许多标准库中的用户自定义字面量,特别是在 `<chrono>` 头文件中,用于处理时间间隔。例如: ```cpp #include <iostream> #include <chrono> #include <thread> int main() { using namespace std::literals::chrono_literals; // 使用自定义字面量表示时间间隔 std::this_thread::sleep_for(2s); // 等待2秒 std::cout << "Waited for 2 seconds" << std::endl; return 0; } ``` 在这个例子中,`2s` 表示2秒的时间间隔,`s` 是 `std::chrono::seconds` 的自定义字面量后缀。类似地,还可以使用 `ms`(毫秒)、`us`(微秒)等后缀[^1]。 ##### 4. **注意事项** - **命名约定**:为了防止与标准库或其他第三方库冲突,建议所有自定义字面量后缀都以 `_` 开头。例如,`_m` 而不是 `m`。 - **避免混淆**:不要使用与现有标准字面量相同的后缀,如 `UL`(无符号长整型),这可能会导致编译器警告或不可预期的行为。 - **头文件依赖**:某些自定义字面量需要包含特定的头文件,例如 `<chrono>` 或 `<string>`,并且可能需要启用C++14或更高版本的支持。 #### 示例总结 以下是一些常见的自定义字面量示例,展示了如何在实际项目中应用这些特性: 1. **时间间隔**(使用 `<chrono>`): ```cpp #include <iostream> #include <chrono> #include <thread> int main() { using namespace std::literals::chrono_literals; std::this_thread::sleep_for(1s); // 等待1秒 std::cout << "Slept for 1 second" << std::endl; auto duration = 500ms; // 500毫秒 std::cout << "Duration: " << duration.count() << " ms" << std::endl; return 0; } ``` 2. **自定义单位**(如米、千克): ```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; // 10.5米 long double weight = 75.3_kg; // 75.3千克 std::cout << "Length: " << length << " m" << std::endl; std::cout << "Weight: " << weight << " kg" << std::endl; return 0; } ``` 3. **字符串拼接**(使用 `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; } ``` ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值