【C++ Primer】第十七章:标准库特殊设施

标准库特殊设施涵盖了 C++ 标准库中一些非常实用但相对独立的组件,这些工具能极大提升编程效率和代码质量。

1. tuple 类型

基本用法

cpp 复制代码
#include <tuple>
#include <string>
#include <iostream>

void tuple_basic_demo() {
    // 创建 tuple
    std::tuple<int, double, std::string> t1(42, 3.14, "hello");
    
    // 使用 make_tuple(自动推导类型)
    auto t2 = std::make_tuple(1, 2.5, "world", 'a');
    
    // 访问元素(编译时确定索引)
    std::cout << "t1[0]: " << std::get<0>(t1) << std::endl;  // 42
    std::cout << "t1[1]: " << std::get<1>(t1) << std::endl;  // 3.14
    std::cout << "t1[2]: " << std::get<2>(t1) << std::endl;  // hello
    
    // 获取 tuple 大小
    std::cout << "t1 size: " << std::tuple_size<decltype(t1)>::value << std::endl;
    
    // 按类型访问(类型必须唯一)
    std::cout << "string element: " << std::get<std::string>(t1) << std::endl;
}

tuple 的实用操作

cpp 复制代码
#include <functional>

void tuple_operations_demo() {
    auto t1 = std::make_tuple(1, 2.5, "hello");
    auto t2 = std::make_tuple(2, 3.14, "world");
    
    // 比较操作
    if (t1 < t2) {
        std::cout << "t1 < t2" << std::endl;
    }
    
    // 连接 tuple(C++11 之后)
    auto t3 = std::tuple_cat(t1, t2, std::make_tuple('x', 'y'));
    
    // 解包 tuple
    int a;
    double b;
    std::string c;
    std::tie(a, b, c) = t1;  // a=1, b=2.5, c="hello"
    std::cout << "a=" << a << ", b=" << b << ", c=" << c << std::endl;
    
    // 结构化绑定(C++17)
    auto [x, y, z] = t2;
    std::cout << "x=" << x << ", y=" << y << ", z=" << z << std::endl;
}

tuple 与函数返回多值

cpp 复制代码
#include <vector>
#include <algorithm>

// 返回多个值
std::tuple<double, double, double> statistics(const std::vector<double>& data) {
    if (data.empty()) {
        return std::make_tuple(0.0, 0.0, 0.0);
    }
    
    double sum = std::accumulate(data.begin(), data.end(), 0.0);
    double mean = sum / data.size();
    
    auto [min_it, max_it] = std::minmax_element(data.begin(), data.end());
    double min_val = *min_it;
    double max_val = *max_it;
    
    return std::make_tuple(mean, min_val, max_val);
}

void tuple_return_demo() {
    std::vector<double> numbers = {1.0, 2.5, 3.7, 0.5, 4.2};
    
    // C++17 结构化绑定
    auto [mean, min_val, max_val] = statistics(numbers);
    
    std::cout << "Mean: " << mean << std::endl;
    std::cout << "Min: " << min_val << std::endl;
    std::cout << "Max: " << max_val << std::endl;
    
    // C++11/14 方式
    double m1, m2, m3;
    std::tie(m1, m2, m3) = statistics(numbers);
}

2. bitset 类型

基本操作

cpp 复制代码
#include <bitset>
#include <string>

void bitset_basic_demo() {
    // 创建 bitset
    std::bitset<8> b1;           // 8位,全0
    std::bitset<16> b2(0xFFFF);  // 从整数初始化
    std::bitset<32> b3("1100");  // 从字符串初始化
    
    std::cout << "b1: " << b1 << std::endl;  // 00000000
    std::cout << "b2: " << b2 << std::endl;  // 1111111111111111
    std::cout << "b3: " << b3 << std::endl;  // 00000000000000000000000000001100
    
    // 设置位
    b1.set(0);                   // 设置第0位
    b1.set(3, true);             // 设置第3位为1
    b1.set();                    // 设置所有位为1
    
    // 重置位
    b1.reset(0);                 // 重置第0位
    b1.reset();                  // 重置所有位
    
    // 翻转位
    b1.flip(0);                  // 翻转第0位
    b1.flip();                   // 翻转所有位
    
    // 访问位
    bool bit0 = b1[0];           // 访问第0位
    b1[1] = true;                // 设置第1位
    
    // 测试位
    if (b1.test(0)) {
        std::cout << "Bit 0 is set" << std::endl;
    }
    
    // 统计
    std::cout << "Number of 1s: " << b1.count() << std::endl;
    std::cout << "Total bits: " << b1.size() << std::endl;
    std::cout << "Any bit set: " << b1.any() << std::endl;
    std::cout << "All bits set: " << b1.all() << std::endl;
    std::cout << "No bits set: " << b1.none() << std::endl;
}

bitset 应用:权限系统

cpp 复制代码
class PermissionSystem {
public:
    enum Permissions {
        READ = 0,
        WRITE = 1, 
        EXECUTE = 2,
        DELETE = 3,
        SHARE = 4,
        TOTAL_PERMISSIONS = 5
    };
    
private:
    std::bitset<TOTAL_PERMISSIONS> permissions;
    
public:
    void grant(Permissions p) {
        permissions.set(p);
    }
    
    void revoke(Permissions p) {
        permissions.reset(p);
    }
    
    bool has(Permissions p) const {
        return permissions.test(p);
    }
    
    void toggle(Permissions p) {
        permissions.flip(p);
    }
    
    void clear() {
        permissions.reset();
    }
    
    std::string to_string() const {
        return permissions.to_string();
    }
};

void bitset_application_demo() {
    PermissionSystem user_perms;
    
    user_perms.grant(PermissionSystem::READ);
    user_perms.grant(PermissionSystem::WRITE);
    user_perms.grant(PermissionSystem::SHARE);
    
    std::cout << "Permissions: " << user_perms.to_string() << std::endl;
    std::cout << "Can read: " << user_perms.has(PermissionSystem::READ) << std::endl;
    std::cout << "Can execute: " << user_perms.has(PermissionSystem::EXECUTE) << std::endl;
    
    user_perms.toggle(PermissionSystem::WRITE);
    std::cout << "After toggle WRITE: " << user_perms.to_string() << std::endl;
}

3. 正则表达式库

基本匹配

cpp 复制代码
#include <regex>
#include <string>

void regex_basic_demo() {
    std::string text = "Quick brown fox jumps over the lazy dog";
    
    // 简单搜索
    std::regex word_regex("\\b\\w+\\b");  // 单词边界
    auto words_begin = std::sregex_iterator(text.begin(), text.end(), word_regex);
    auto words_end = std::sregex_iterator();
    
    std::cout << "Words found: " << std::distance(words_begin, words_end) << std::endl;
    
    for (auto i = words_begin; i != words_end; ++i) {
        std::smatch match = *i;
        std::cout << match.str() << " ";
    }
    std::cout << std::endl;
    
    // 精确匹配
    std::regex fox_regex("fox");
    if (std::regex_search(text, fox_regex)) {
        std::cout << "Found 'fox' in the text" << std::endl;
    }
    
    // 匹配检查
    std::regex exact_regex("^Quick.*dog$");
    if (std::regex_match(text, exact_regex)) {
        std::cout << "Text matches the pattern" << std::endl;
    }
}

分组和替换

cpp 复制代码
void regex_advanced_demo() {
    // 分组提取
    std::string date = "2024-01-15";
    std::regex date_regex(R"((\d{4})-(\d{2})-(\d{2}))");
    std::smatch match;
    
    if (std::regex_match(date, match, date_regex)) {
        std::cout << "Full match: " << match[0] << std::endl;
        std::cout << "Year: " << match[1] << std::endl;
        std::cout << "Month: " << match[2] << std::endl;
        std::cout << "Day: " << match[3] << std::endl;
    }
    
    // 字符串替换
    std::string text = "C++ is better than Java";
    std::regex lang_regex("Java");
    std::string result = std::regex_replace(text, lang_regex, "Python");
    std::cout << "After replacement: " << result << std::endl;
    
    // 格式化替换
    std::string phone = "Call me at (123) 456-7890";
    std::regex phone_regex(R"(\((\d{3})\)\s*(\d{3})-(\d{4}))");
    std::string formatted = std::regex_replace(phone, phone_regex, "$1-$2-$3");
    std::cout << "Formatted phone: " << formatted << std::endl;
    
    // 邮箱验证
    std::regex email_regex(R"(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b)");
    std::string email = "user@example.com";
    if (std::regex_match(email, email_regex)) {
        std::cout << "Valid email: " << email << std::endl;
    }
}

4. 随机数库

现代随机数生成

cpp 复制代码
#include <random>
#include <chrono>

void random_number_demo() {
    // 随机数引擎(使用时间作为种子)
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::default_random_engine generator(seed);
    
    // 均匀分布
    std::uniform_int_distribution<int> int_dist(1, 100);     // 1-100 整数
    std::uniform_real_distribution<double> real_dist(0.0, 1.0); // 0-1 实数
    
    std::cout << "Random integers: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << int_dist(generator) << " ";
    }
    std::cout << std::endl;
    
    std::cout << "Random reals: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << real_dist(generator) << " ";
    }
    std::cout << std::endl;
    
    // 正态分布
    std::normal_distribution<double> normal_dist(0.0, 1.0);  // 均值0,标准差1
    std::cout << "Normal distribution: ";
    for (int i = 0; i < 5; ++i) {
        std::cout << normal_dist(generator) << " ";
    }
    std::cout << std::endl;
    
    // 布尔分布(50% 概率)
    std::bernoulli_distribution bool_dist(0.5);
    std::cout << "Coin flips: ";
    for (int i = 0; i < 10; ++i) {
        std::cout << (bool_dist(generator) ? "Heads" : "Tails") << " ";
    }
    std::cout << std::endl;
}

随机数应用:抽奖系统

cpp 复制代码
#include <vector>
#include <algorithm>

class LotterySystem {
private:
    std::mt19937 generator;
    
public:
    LotterySystem() : generator(std::random_device{}()) {}
    
    // 从范围内抽取不重复的数字
    std::vector<int> draw_numbers(int min, int max, int count) {
        std::vector<int> all_numbers;
        for (int i = min; i <= max; ++i) {
            all_numbers.push_back(i);
        }
        
        std::shuffle(all_numbers.begin(), all_numbers.end(), generator);
        all_numbers.resize(count);
        
        std::sort(all_numbers.begin(), all_numbers.end());
        return all_numbers;
    }
    
    // 从列表中随机选择
    template<typename T>
    T select_random(const std::vector<T>& items) {
        std::uniform_int_distribution<size_t> dist(0, items.size() - 1);
        return items[dist(generator)];
    }
};

void lottery_demo() {
    LotterySystem lottery;
    
    // 抽奖:从1-49中抽取6个数字
    auto numbers = lottery.draw_numbers(1, 49, 6);
    std::cout << "Lottery numbers: ";
    for (int num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    
    // 随机选择
    std::vector<std::string> prizes = {"Car", "TV", "Phone", "Book", "Nothing"};
    std::cout << "You won: " << lottery.select_random(prizes) << std::endl;
}

5. IO 库高级功能

格式化输出

cpp 复制代码
#include <iomanip>

void formatting_demo() {
    double pi = 3.141592653589793;
    int number = 255;
    
    // 设置精度
    std::cout << "Default: " << pi << std::endl;
    std::cout << "Fixed(2): " << std::fixed << std::setprecision(2) << pi << std::endl;
    std::cout << "Scientific: " << std::scientific << pi << std::endl;
    
    // 恢复默认
    std::cout << std::defaultfloat;
    
    // 设置宽度和对齐
    std::cout << std::setw(10) << number << std::endl;
    std::cout << std::setw(10) << std::left << number << std::endl;
    std::cout << std::setw(10) << std::right << number << std::endl;
    
    // 填充字符
    std::cout << std::setw(10) << std::setfill('*') << number << std::endl;
    
    // 进制输出
    std::cout << "Decimal: " << number << std::endl;
    std::cout << "Hex: " << std::hex << number << std::endl;
    std::cout << "Octal: " << std::oct << number << std::endl;
    
    // 恢复十进制
    std::cout << std::dec;
    
    // 布尔值输出
    bool flag = true;
    std::cout << "Default bool: " << flag << std::endl;
    std::cout << "Boolalpha: " << std::boolalpha << flag << std::endl;
}

文件流操作

cpp 复制代码
#include <fstream>
#include <sstream>

void file_io_demo() {
    // 写入文件
    std::ofstream outfile("example.txt");
    if (outfile) {
        outfile << "Line 1: Hello World" << std::endl;
        outfile << "Line 2: 3.14159" << std::endl;
        outfile << "Line 3: 42" << std::endl;
        outfile.close();
    }
    
    // 读取文件
    std::ifstream infile("example.txt");
    std::string line;
    if (infile) {
        while (std::getline(infile, line)) {
            std::cout << "Read: " << line << std::endl;
        }
        infile.close();
    }
    
    // 字符串流
    std::string data = "John 25 85.5";
    std::istringstream iss(data);
    std::string name;
    int age;
    double score;
    
    iss >> name >> age >> score;
    std::cout << "Name: " << name << ", Age: " << age << ", Score: " << score << std::endl;
    
    // 字符串流构建字符串
    std::ostringstream oss;
    oss << "Result: " << 42 << " " << 3.14 << " " << std::boolalpha << true;
    std::string result_str = oss.str();
    std::cout << "Built string: " << result_str << std::endl;
}

6. 实践项目:配置文件解析器

cpp 复制代码
#include <map>
#include <sstream>

class ConfigParser {
private:
    std::map<std::string, std::string> config;
    
public:
    bool load(const std::string& filename) {
        std::ifstream file(filename);
        if (!file) {
            return false;
        }
        
        std::string line;
        std::regex config_regex(R"(^\s*([\w\.-]+)\s*=\s*(.*?)\s*$)");
        std::regex comment_regex(R"(^\s*#)");
        
        while (std::getline(file, line)) {
            // 跳过空行和注释
            if (line.empty() || std::regex_match(line, comment_regex)) {
                continue;
            }
            
            std::smatch match;
            if (std::regex_match(line, match, config_regex)) {
                config[match[1]] = match[2];
            }
        }
        
        return true;
    }
    
    template<typename T>
    T get(const std::string& key, const T& default_value = T()) const {
        auto it = config.find(key);
        if (it == config.end()) {
            return default_value;
        }
        
        std::istringstream iss(it->second);
        T value;
        if (!(iss >> value)) {
            return default_value;
        }
        return value;
    }
    
    // 字符串特化
    std::string get(const std::string& key, const std::string& default_value = "") const {
        auto it = config.find(key);
        if (it == config.end()) {
            return default_value;
        }
        return it->second;
    }
    
    // 布尔值特化
    bool get_bool(const std::string& key, bool default_value = false) const {
        auto it = config.find(key);
        if (it == config.end()) {
            return default_value;
        }
        
        std::string value = it->second;
        std::transform(value.begin(), value.end(), value.begin(), ::tolower);
        
        if (value == "true" || value == "1" || value == "yes" || value == "on") {
            return true;
        } else if (value == "false" || value == "0" || value == "no" || value == "off") {
            return false;
        }
        
        return default_value;
    }
};

void config_parser_demo() {
    ConfigParser parser;
    if (parser.load("config.txt")) {
        std::string name = parser.get("name", "Unknown");
        int port = parser.get("port", 8080);
        double timeout = parser.get("timeout", 30.0);
        bool debug = parser.get_bool("debug", false);
        
        std::cout << "Name: " << name << std::endl;
        std::cout << "Port: " << port << std::endl;
        std::cout << "Timeout: " << timeout << std::endl;
        std::cout << "Debug: " << std::boolalpha << debug << std::endl;
    }
}

最佳实践总结

  1. 优先使用现代随机数库 而不是 rand()
  2. 使用 regex 进行复杂的字符串处理
  3. tuple 适合返回多个相关值
  4. bitset 适合存储固定大小的标志集合
  5. 掌握 IO 格式化提升输出质量

使用 C++ 标准库中的高级工具解决复杂问题,大大提升编程效率!

相关推荐
神龙斗士2405 小时前
继承和组合
java·开发语言
一点七加一6 小时前
Harmony鸿蒙开发0基础入门到精通Day01--JavaScript篇
开发语言·javascript·华为·typescript·ecmascript·harmonyos
1379号监听员_6 小时前
嵌入式软件架构--按键消息队列3(测试)
开发语言·stm32·单片机·嵌入式硬件·架构
阿登林6 小时前
C# iText7与iTextSharp导出PDF对比
开发语言·pdf·c#
qq_433554546 小时前
C++ 双向循环链表
开发语言·c++·链表
一只侯子6 小时前
Tuning——CC调试(适用高通)
开发语言·图像处理·笔记·学习·算法
丁浩6666 小时前
Python机器学习---1.数据类型和算法:线性回归
开发语言·python·机器学习·线性回归
那年窗外下的雪.6 小时前
鸿蒙ArkUI布局与样式进阶(十二)——自定义TabBar + class类机制全解析(含手机商城底部导航案例)
开发语言·前端·javascript·华为·智能手机·harmonyos·arkui
Larry_Yanan6 小时前
QML学习笔记(四十六)QML与C++交互:Q_PROPERTY宏映射
c++·笔记·qt·学习·ui·交互