C++14入门

C++14 核心特性详解

C++14 是 C++11 主要版本之后的次要版本,主要包含语言和标准库的改进与缺陷修复,增强了代码简洁性和表达能力。

目录

C++14

  • [C++14 核心特性详解](#C++14 核心特性详解)
    • 目录
    • [1. 变量模板](#1. 变量模板)
    • [2. 泛型lambda表达式](#2. 泛型lambda表达式)
    • [3. 函数返回类型推导](#3. 函数返回类型推导)
    • [4. 二进制字面量](#4. 二进制字面量)
    • [5. 数字分隔符](#5. 数字分隔符)
    • [6. 使用非静态成员初始化器的聚合类](#6. 使用非静态成员初始化器的聚合类)
    • [7. std::exchange](#7. std::exchange)
    • [8. std::make_unique](#8. std::make_unique)
    • [9. std::integer_sequence](#9. std::integer_sequence)
    • [10. std::quoted](#10. std::quoted)
    • [11. shared_timed_mutex 和 shared_mutex](#11. shared_timed_mutex 和 shared_mutex)
    • [12. 字面量后缀](#12. 字面量后缀)

1. 变量模板

C++14 允许模板不仅用于类和函数,还可以用于变量,使得编译期常量可以模板化。

cpp 复制代码
#include <iostream>
using namespace std;

// 定义变量模板
template<typename T>
constexpr T pi = T(3.14159265358979323L);

// 使用变量模板
int main() {
    std::cout.precision(10);
    std::cout << "float π: " << pi<float> << std::endl;
    std::cout.precision(10);
    std::cout << "double π: " << pi<double> << std::endl;
    return 0;
}

2. 泛型lambda表达式

C++14 允许lambda表达式使用auto作为参数类型,使其成为泛型。包括:

  • auto& 左值引用的形参
  • auto&& 万能引用的形参
  • auto&&... 可变模板的万能引用
cpp 复制代码
// 泛型lambda
auto getMax = const auto& x, const auto& y {
    return x > y ? x : y;
};

// 初始化捕获
int i = 1;
auto f1 =  {  // 创建新变量i,用表达式i+1初始化
    std::cout << "这个i只在lambda函数体内部可见和使用: " << i << std::endl;
};

3. 函数返回类型推导

C++14 直接支持auto推导函数返回类型,无需尾置返回类型。

cpp 复制代码
// 返回类型推导
auto add(int x, int y) {
    return x + y;  // 推导为int
}

// 多返回语句必须推导出相同类型
auto f1(int x) {
    if (x > 0)
        return 1;  // int
    else
        return 2;  // int
}

// decltype(auto) 用于完美转发返回类型
template<typename F, typename... Args>
decltype(auto) call(F&& f, Args&&... args) {
    return std::forward<F>(f)(std::forward<Args>(args)...);
}

4. 二进制字面量

C++14 增加了二进制字面量表示,提高代码可读性。

cpp 复制代码
int d = 42;       // 十进制
int o = 052;      // 八进制
int x = 0x2a;     // 十六进制
int X = 0X2A;     // 十六进制
int b = 0b101010; // 二进制,C++14新增

5. 数字分隔符

C++14 允许在数字中使用单引号作为分隔符,提高大数字的可读性。

cpp 复制代码
int million = 100'0000;
long hexValue = 0xDEAD'BEEF;
double pi = 3.141'592'653'59;
unsigned long long bigBinary = 0b1010'1010'1010'1010;

6. 使用非静态成员初始化器的聚合类

C++14 允许聚合类包含默认的非静态成员初始化器。

cpp 复制代码
struct Employee {
    std::string name = "Unknown";
    int id = -1;
    double salary = 0.0;
};

// 使用
Employee e1 = {"xxx", 1, 1.1};  // C++98风格
Employee e2{"John"};           // name="John", id=-1, salary=0.0
Employee e3{"Alice", 123};     // name="Alice", id=123, salary=0.0
Employee e4{};                 // 全部采用初始化器

7. std::exchange

std::exchange 是 C++14 在 <utility> 头文件中引入的实用函数模板,提供简洁高效的方式来替换对象的值并返回其旧值。

cpp 复制代码
#include <utility>

// 以 new_value 替换 obj 的值,并返回 obj 的旧值
template<class T, class U = T>
T exchange(T& obj, U&& new_value) {
    T old = std::move(obj);
    obj = std::forward<U>(new_value);
    return old;
}

// 使用示例
int x = 10;
int old = std::exchange(x, 20);  // x变为20,old为10

8. std::make_unique

std::make_unique 是C++14引入的智能指针创建工具,用于安全地创建和管理std::unique_ptr对象。

cpp 复制代码
#include <memory>

// 创建单个对象
auto ptr1 = std::make_unique<int>();     // 值初始化为0
auto ptr2 = std::make_unique<int>(42);   // 初始化为42

// 创建数组
auto arr = std::make_unique<int[]>(5);   // 5个int,值初始化为0

// 创建结构体
struct Vec3 { int x, y, z; };
auto v = std::make_unique<Vec3>(1, 2, 3);

9. std::integer_sequence

std::integer_sequence 是C++14引入的模板类,用于在编译时表示一个整数序列,是模板元编程和编译时计算的有用工具。

cpp 复制代码
#include <utility>
#include <iostream>

template<typename Array, std::size_t... I>
void print_array_impl(const Array& arr, std::index_sequence<I...>) {
    ((std::cout << arr[I] << ' '), ...);
}

template<typename T, std::size_t N>
void print_array(const std::array<T, N>& arr) {
    print_array_impl(arr, std::make_index_sequence<N>{});
}

int main() {
    std::array<int, 4> arr{1, 2, 3, 4};
    print_array(arr);  // 输出: 1 2 3 4
    return 0;
}

10. std::quoted

std::quoted 是C++14引入的I/O操纵器,用于简化带引号字符串的输入输出操作。

cpp 复制代码
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>

int main() {
    // 输出带引号的字符串
    std::string text = "Hello, World!";
    std::cout << "Without quoted: " << text << std::endl;
    std::cout << "With quoted: " << std::quoted(text) << std::endl;
    // 输出:
    // Without quoted: Hello, World!
    // With quoted: "Hello, World!"
    
    // 输入带引号的字符串
    std::istringstream input("\"Hello, World!\"");
    input >> std::quoted(text);
    std::cout << "Extracted: " << text << std::endl;
    // 输出: Extracted: Hello, World!
    
    return 0;
}

11. shared_timed_mutex 和 shared_mutex

C++14 提供了shared_timed_mutex,C++17 提供了shared_mutex,解决读写者问题。

cpp 复制代码
#include <iostream>
#include <shared_mutex>
#include <thread>
#include <vector>

class ThreadSafeCounter {
public:
    ThreadSafeCounter() = default;
    
    // 多个线程可以同时读取
    unsigned int get() const {
        std::shared_lock<std::shared_timed_mutex> lock(mutex_);
        return value_;
    }
    
    // 只有一个线程可以修改
    void increment() {
        std::unique_lock<std::shared_timed_mutex> lock(mutex_);
        ++value_;
    }
    
private:
    mutable std::shared_timed_mutex mutex_;
    unsigned int value_ = 0;
};

int main() {
    ThreadSafeCounter counter;
    
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back( {
            for (int j = 0; j < 100; ++j) {
                counter.increment();
            }
        });
    }
    
    for (auto& t : threads) {
        t.join();
    }
    
    std::cout << "Final value: " << counter.get() << std::endl;
    return 0;
}

12. 字面量后缀

C++14 扩展了字面量后缀,增加了时间字面量和字符串字面量。

标准库字面量

cpp 复制代码
#include <chrono>
#include <string>
#include <string_view>

using namespace std::literals;

// 时间字面量
auto duration1 = 100ms;    // 100毫秒
auto duration2 = 5h;       // 5小时
auto duration3 = 1.5min;   // 1.5分钟

// 字符串字面量
auto str1 = "hello"s;     // std::string
auto str2 = "world"sv;    // std::string_view (C++17)

用户定义字面量

cpp 复制代码
// 用户定义字面量
constexpr long double operator"" _km(long double x) {
    return x * 1000.0;  // 将公里转换为米
}

constexpr long double operator"" _pi(long double x) {
    return x * 3.14159265358979323846L;
}

int main() {
    auto distance = 5.0_km;  // 相当于 5000.0L
    auto angle = 2.0_pi;     // 相当于 6.28318530717958647692L
    return 0;
}
相关推荐
行稳方能走远1 小时前
从轮询到回调再到观察者——嵌入式应用层感知底层变化的三种姿势
c++
YLXA2 小时前
1.helle_cuda学习
linux·学习·算法
Storynone2 小时前
【Day21】LeetCode:93. 复原IP地址,78. 子集,90. 子集 II
python·算法·leetcode
知无不研2 小时前
中介者模式
c++·设计模式·中介者模式
ab1515172 小时前
3.14二刷基础93 94 83 98 99 完成进阶40 43
算法
nananaij2 小时前
【LeetCode-01 两数之和 python解法】
开发语言·python·算法·leetcode
crescent_悦2 小时前
PTA C++:正整数A+B
数据结构·c++·算法
丶小鱼丶2 小时前
数据结构和算法之【链表】
java·数据结构·算法
礼拜天没时间.2 小时前
力扣热题100实战 | 第31期:下一个排列——数组规律的极致探索
java·算法·leetcode·字典序·原地算法·力扣热题100