【C++】C++11:其他重要特性

目录

一、列表初始化

[1.1 C++98传统的初始化方式](#1.1 C++98传统的初始化方式)

[1.2 C++11的列表初始化](#1.2 C++11的列表初始化)

[1.3 std::initializer_list](#1.3 std::initializer_list)
二、可变参数模板

[2.1 基本语法及原理](#2.1 基本语法及原理)

[2.2 包扩展](#2.2 包扩展)

[2.3 emplace系列接口](#2.3 emplace系列接口)
三、新的类功能

[3.1 默认的移动构造和移动赋值](#3.1 默认的移动构造和移动赋值)

[3.2 成员变量声明时给缺省值](#3.2 成员变量声明时给缺省值)

[3.3 default和delete](#3.3 default和delete)

[3.4 final与override](#3.4 final与override)
四、STL中一些变化
五、lambda表达式

[5.1 lambda表达式语法](#5.1 lambda表达式语法)

[5.2 捕捉列表](#5.2 捕捉列表)

[5.3 lambda的应用](#5.3 lambda的应用)

[5.4 lambda的原理](#5.4 lambda的原理)
六、包装器

[6.1 function](#6.1 function)

[6.2 bind](#6.2 bind)
七、总结


一、列表初始化

1.1 C++98传统的初始化方式

在C++98中,主要支持以下几种初始化方式:

cpp 复制代码
struct Point
{
    int _x;
    int _y;
};

int main()
{
    // 数组初始化
    int array1[] = { 1, 2, 3, 4, 5 };
    int array2[5] = { 0 };
    
    // 结构体初始化
    Point p = { 1, 2 };
    
    return 0;
}

C++98的初始化方式存在局限性:

  • 只能用于数组和简单的结构体
  • 对于类对象的初始化不够灵活
  • 初始化方式不统一

1.2 C++11的列表初始化

C++11引入了列表初始化 (也称为统一初始化),试图实现一切对象皆可用{}初始化。

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

struct Point
{
    int _x;
    int _y;
};

class Date
{
public:
    Date(int year = 1, int month = 1, int day = 1)
    :_year(year)
    , _month(month)
    , _day(day)
    {
        cout << "Date(int year, int month, int day)" << endl;
    }
    
    Date(const Date& d)
    :_year(d._year)
    , _month(d._month)
    , _day(d._day)
    {
        cout << "Date(const Date& d)" << endl;
    }
    
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    // C++11支持的列表初始化
    // 内置类型支持
    int x1 = { 2 };
    
    // 自定义类型支持
    // 本质是用{2025, 1, 1}构造临时对象,编译器优化后直接构造d1
    Date d1 = { 2025, 1, 1 };
    
    // 引用临时对象
    const Date& d2 = { 2024, 7, 25 };
    
    // 单参数时的类型转换
    Date d3 = { 2025 };
    Date d4 = 2025;  // C++98也支持
    
    // 省略=的列表初始化
    Point p1 { 1, 2 };
    int x2 { 2 };
    Date d6 { 2024, 7, 25 };
    const Date& d7 { 2024, 7, 25 };
    
    // 不支持省略=的传统初始化
    // Date d8 2025;  // 错误!
    
    // 在容器中使用列表初始化的便利性
    vector<Date> v;
    v.push_back(d1);
    v.push_back(Date(2025, 1, 1));
    
    // 使用列表初始化更简洁
    v.push_back({ 2025, 1, 1 });
    
    return 0;
}

列表初始化的优势

  • 统一的初始化语法
  • 支持省略=
  • 在容器操作中更加方便
  • 防止窄化转换(如int x{3.14};会编译错误)

1.3 std::initializer_list

C++11库中提出了一个 std::initializer_list 的类,用于支持任意数量参数的初始化。这个类的本质是底层开一个数组,将数据拷贝过来,内部有两个指针分别指向数组的开始和结束。

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

int main()
{
    // initializer_list的基本使用
    std::initializer_list<int> myList;
    myList = { 10, 20, 30 };
    cout << sizeof(myList) << endl;  // 通常为2个指针的大小
    
    // 验证initializer_list的存储位置
    int i = 0;
    cout << myList.begin() << endl;
    cout << myList.end() << endl;
    cout << &i << endl;
    
    // 容器使用initializer_list初始化
    vector<int> v1({ 1, 2, 3, 4, 5 });      // 直接构造
    vector<int> v2 = { 1, 2, 3, 4, 5 };     // 构造+优化
    const vector<int>& v3 = { 1, 2, 3, 4, 5 };
    
    // map使用initializer_list初始化
    map<string, string> dict = { {"sort", "排序"}, {"string", "字符串"} };
    
    // initializer_list版本的赋值
    v1 = { 10, 20, 30, 40, 50 };
    
    return 0;
}

若容器支持一个 std::initializer_list 的构造函数,也就支持任意多个值构成的 {x1, x2, x3, ...}进行初始化。STL 中的容器支持任意多个值构成的 {x1, x2, x3, ...}进行初始化,就是通过 std::initializer_list 的构造函数支持的。

cpp 复制代码
// STL容器都增加了initializer_list构造函数
vector(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());
list(initializer_list<value_type> il, const allocator_type& alloc = allocator_type());
map(initializer_list<value_type> il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

// 以及对应的赋值运算符重载
vector& operator=(initializer_list<value_type> il);
map& operator=(initializer_list<value_type> il);

实现原理

cpp 复制代码
template<class T>
class vector {
public:
    typedef T* iterator;
    
    vector(initializer_list<T> L)
    {
        for (auto e : L)
            push_back(e);
    }
    
private:
    iterator _start = nullptr;
    iterator _finish = nullptr;
    iterator _endofstorage = nullptr;
};

二、可变参数模板

2.1 基本语法及原理

可变参数模板支持任意数量和类型的参数。

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

// 计算参数包中参数的个数
template <class ...Args>
void Print(Args&&... args) { 		   
    cout << "参数个数: " << sizeof...(args) << endl;
}

int main() 
{
    double x = 2.2;
    
    Print();                           // 0个参数
    Print(1);                          // 1个参数  
    Print(1, string("xxxxx"));         // 2个参数
    Print(1.1, string("xxxxx"), x);    // 3个参数
    
    return 0;
}

2.2 包扩展

  • 对于一个参数包,我们除了能计算他的参数个数,我们能做的唯一的事情就是扩展它,当扩展一个包时,我们还要提供用于每个扩展元素的模式,扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式的右边放一个省略号(...)来触发扩展操作。底层的实现细节如下图所示。
  • C++11支持直接将参数包依次展开依次作为实参给一个函数去处理。
cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 递归终止函数
void ShowList() {
    cout << endl;
}

// 递归展开参数包
template <class T, class ...Args>
void ShowList(T x, Args... args) {
    cout << x << " ";
    ShowList(args...);  // 递归调用
}

// 包装函数
template <class ...Args>
void Print(Args... args) {
    ShowList(args...);
}

int main() 
{
    Print();
    Print(1);
    Print(1, string("xxxxx"));
    Print(1, string("xxxxx"), 2.2);
    
    return 0;
}

2.3 emplace系列接口

emplace系列接口支持直接在容器中构造对象,避免不必要的拷贝。

cpp 复制代码
#include <list>
#include <string>
#include <utility>
using namespace std;

int main() 
{
    list<pair<string, int>> lt;
    
    // 传统方式 - 构造pair + 拷贝/移动构造
    pair<string, int> kv("苹果", 1);
    lt.push_back(kv);                    // 拷贝构造
    lt.push_back(move(kv));              // 移动构造
    lt.push_back({"香蕉", 2});           // 移动构造
    
    // emplace方式 - 直接构造
    lt.emplace_back("橙子", 3);          // 直接构造,最高效
    lt.emplace_back(string("菠萝"), 4);  // 移动构造
    
    return 0;
}

三、新的类功能

3.1 默认的移动构造和移动赋值

C++11新增了两个默认成员函数:移动构造函数和移动赋值运算符。

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

namespace codebyv {
    // 简化的string实现
    class string {
    public:
        string(const char* str = "") {}
        string(const string& s) { cout << "拷贝构造" << endl; }
        string(string&& s) { cout << "移动构造" << endl; }
        string& operator=(const string& s) { cout << "拷贝赋值" << endl; return *this; }
        string& operator=(string&& s) { cout << "移动赋值" << endl; return *this; }
    };
}

class Person {
public:
    Person(const char* name = "", int age = 0)
    : _name(name)
    , _age(age)
    {}
    
    // 如果注释掉拷贝构造/拷贝赋值/析构函数,编译器会自动生成移动构造和移动赋值
    
private:
    codebyv::string _name;
    int _age;
};

int main()
{
    Person s1;
    Person s2 = s1;              // 拷贝构造
    Person s3 = std::move(s1);   // 移动构造(如果生成)
    Person s4;
    s4 = std::move(s2);          // 移动赋值(如果生成)
    
    return 0;
}

默认移动操作的生成规则

  • 如果没有用户声明的拷贝构造、拷贝赋值、析构函数,编译器会自动生成移动构造和移动赋值
  • 对于内置类型成员:按字节拷贝
  • 对于自定义类型成员:如果该类型有移动构造/移动赋值,则调用移动版本;否则调用拷贝版本

3.2 成员变量声明时给缺省值

C++11支持在类定义中直接给成员变量缺省值。

cpp 复制代码
class Student {
private:
    string _name = "Unknown";  // 声明时给缺省值
    int _age = 0;              // 声明时给缺省值
    vector<int> _scores{90, 85, 95};  // 列表初始化
    
public:
    Student() = default;  // 使用默认构造函数
    
    Student(const string& name, int age) 
    : _name(name)         // 初始化列表会覆盖缺省值
    , _age(age)
    {}
};
  • 如果没有在初始化列表中显式初始化,就会使用缺省值
  • 初始化列表的初始化会覆盖缺省值

3.3 default和delete

C++11提供了更好的控制默认函数生成的机制。

cpp 复制代码
class Person {
public:
    Person(const char* name = "", int age = 0)
    :_name(name)
    , _age(age)
    {}
    
    // 用户定义了拷贝构造,默认不会生成移动构造
    Person(const Person& p)
    :_name(p._name)
    ,_age(p._age)
    {}
    
    // 使用default强制生成移动构造
    Person(Person&& p) = default;
    
    // 使用delete禁止拷贝构造
    Person(const Person& p) = delete;
    
private:
    string _name;
    int _age;
};

应用场景

  • = default:显式要求编译器生成默认版本
  • = delete:禁止编译器生成特定函数,用于实现不可拷贝、不可移动等语义

3.4 final与override

cpp 复制代码
class Base {
public:
    virtual void func() final {}    // final禁止派生类重写
};

class Derived : public Base {
public:
    virtual void func() override {}  // override显式指明重写,编译检查
};

四、STL中一些变化

C++11为STL带来了许多新容器和接口改进:

新增容器

  • std::array:固定大小数组
  • std::forward_list:单向链表
  • std::unordered_map/set:哈希表实现的map和set

重要接口改进

  • 支持initializer_list的构造函数和赋值运算符
  • 增加了移动语义相关的push/insert/emplace系列接口
  • 增加了cbegin/cend等const迭代器
cpp 复制代码
#include<vector>
#include<array>
#include<unordered_map>
using namespace std;

int main()
{
    // 使用initializer_list初始化
    vector<int> v = {1, 2, 3, 4, 5};
    array<int, 5> arr = {1, 2, 3, 4, 5};
    unordered_map<string, int> dict = {{"apple", 1}, {"banana", 2}};
    
    // 移动语义接口
    vector<string> vec;
    string s = "hello";
    vec.push_back(move(s));  // 移动而非拷贝
    
    // emplace系列接口
    vec.emplace_back("world");  // 直接构造
    
    return 0;
}

五、lambda表达式

5.1 lambda表达式语法

  • lambda 表达式本质是一个匿名函数对象,跟普通函数不同的是他可以定义在函数内部。
  • lambda 表达式语法使用层而言没有类型,所以我们一般是用auto或者模板参数定义的对象去接收 lambda 对象。

lambda表达式的格式:

cpp 复制代码
[capture-list] (parameters) -> return-type { function-body }
  • [capture-list]:捕捉列表,该列表总是出现在 lambda 函数的开始位置,编译器根据[]来判断接下来的代码是否为 lambda 函数,捕捉列表能够捕捉上下文中的变量供 lambda 函数使用,捕捉列表可以传值和传引用捕捉。捕捉列表为空也不能省略。
  • (parameters):参数列表,与普通函数的参数列表功能类似,如果不需要参数传递,则可以连同()一起省略
  • ->return-type:返回值类型,用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。一般返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  • {function-body}:函数体,函数体内的实现跟普通函数完全类似,在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量,函数体为空也不能省略。
cpp 复制代码
int main()
{
    // 完整的lambda表达式
    auto add1 = [](int x, int y) -> int { return x + y; };
    cout << add1(1, 2) << endl;
    
    // 省略参数列表
    auto func1 = [] { cout << "hello bit" << endl; };
    func1();
    
    // 省略返回类型(编译器推导)
    auto add2 = [](int x, int y) { return x + y; };
    
    // 带引用参数的lambda
    int a = 0, b = 1;
    auto swap1 = [](int& x, int& y) {
        int tmp = x;
        x = y;
        y = tmp;
    };
    swap1(a, b);
    cout << a << ":" << b << endl;
    
    return 0;
}

5.2 捕捉列表

lambda 表达式中默认只能用 lambda 函数体和参数中的变量,如果想用外层作用域中的变量就需要进行捕捉。

三种捕捉方式:
  • 第一种捕捉方式是在捕捉列表中显示的传值捕捉和传引用捕捉 ,捕捉的多个变量用逗号分割。[x, y, &z] 表示xy值捕捉,z引用捕捉。
  • 第二种捕捉方式是在捕捉列表中隐式捕捉 ,我们在捕捉列表写一个=表示隐式值捕捉,在捕捉列表写一个&表示隐式引用捕捉,这样我们 lambda 表达式中用了那些变量,编译器就会自动捕捉那些变量。
  • 第三种捕捉方式是在捕捉列表中混合使用隐式捕捉和显示捕捉[=, &x] 表示其他变量隐式值捕捉,x引用捕捉;[&, x, y] 表示其他变量引用捕捉,xy值捕捉。

捕捉规则

  • 全局变量和静态局部变量不需要捕捉
  • 值捕捉的变量默认有const属性,使用mutable可以取消
  • 混合捕捉时,第一个元素必须是&=,后续显示捕捉方式必须相反
cpp 复制代码
int main()
{
    int a = 0, b = 1, c = 2, d = 3;
    
    // 1. 显式值捕捉
    auto func1 = [a, &b] {  // a值捕捉,b引用捕捉
        // a++;  // 错误:值捕捉的变量默认const
        b++;     // 正确:引用捕捉可以修改
        return a + b;
    };
    
    // 2. 隐式值捕捉
    auto func2 = [=] {  // 隐式值捕捉所有使用的变量
        return a + b + c;
    };
    
    // 3. 隐式引用捕捉
    auto func3 = [&] {  // 隐式引用捕捉所有使用的变量
        a++; b++; c++; d++;
    };
    
    // 4. 混合捕捉
    auto func4 = [&, a, b] {  // 其他引用捕捉,a,b值捕捉
        c++; d++;
        return a + b + c + d;
    };
    
    auto func5 = [=, &a, &b] {  // 其他值捕捉,a,b引用捕捉
        a++; b++;
        return a + b + c + d;
    };
    
    // 5. mutable取消常量性
    auto func6 = [=]() mutable {  // 去掉const,可以修改值捕捉的变量
        a++; b++;  // 修改的是副本,不影响外部变量
        return a + b;
    };
    
    return 0;
}

5.3 lambda的应用

lambda表达式大大简化了可调用对象的定义。

cpp 复制代码
#include<vector>
#include<algorithm>
#include<string>
using namespace std;

struct Goods {
    string _name;
    double _price;
    int _evaluate;
    
    Goods(const char* str, double price, int evaluate)
    :_name(str), _price(price), _evaluate(evaluate)
    {}
};

int main()
{
    vector<Goods> v = { 
        {"苹果", 2.1, 5}, 
        {"香蕉", 3, 4}, 
        {"橙子", 2.2, 3}, 
        {"菠萝", 1.5, 4}
    };
    
    // 使用lambda进行多种排序
    sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
        return g1._price < g2._price;  // 按价格升序
    });
    
    sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
        return g1._price > g2._price;  // 按价格降序
    });
    
    sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
        return g1._evaluate < g2._evaluate;  // 按评价升序
    });
    
    return 0;
}

其他应用场景

  • 回调函数
  • 智能指针的删除器
  • STL算法中的比较参数

5.4 lambda的原理

lambda表达式的底层实现是仿函数,在编译时会被转换为一个匿名类,这个类重载了operator()。

cpp 复制代码
// 原始的lambda表达式
auto lambda = [](int x, int y) { return x + y; };

// 编译器生成的等价代码
class __anonymous_lambda_class {
public:
    auto operator()(int x, int y) const -> int {
        return x + y;
    }
};

__anonymous_lambda_class lambda;

六、包装器

6.1 function

cpp 复制代码
template <class T>
class function;    // undefined

template <class Ret, class... Args>
class function<Ret(Args...)>;
  • std::function 是一个类模板,也是一个包装器。std::function 的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、lambda、bind 表达式等,存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。
  • 函数指针、仿函数、lambda 等可调用对象的类型各不相同,std::function 的优势就是统一类型,对他们都可以进行包装,这样在很多地方就方便声明可调用对象的类型。
cpp 复制代码
#include<functional>
#include<iostream>
using namespace std;

int f(int a, int b) { return a + b; }

struct Functor {
    int operator()(int a, int b) { return a + b; }
};

class Plus {
public:
    Plus(int n = 10) : _n(n) {}
    
    static int plusi(int a, int b) { return a + b; }
    double plusd(double a, double b) { return (a + b) * _n; }
    
private:
    int _n;
};

int main()
{
    // 包装各种可调用对象
    function<int(int, int)> f1 = f;              // 函数指针
    function<int(int, int)> f2 = Functor();      // 函数对象
    function<int(int, int)> f3 = [](int a, int b) { return a + b; };  // lambda
    
    cout << f1(1, 1) << endl;
    cout << f2(1, 1) << endl;
    cout << f3(1, 1) << endl;
    
    // 包装静态成员函数
    function<int(int, int)> f4 = &Plus::plusi;
    cout << f4(1, 1) << endl;
    
    // 包装普通成员函数
    function<double(Plus*, double, double)> f5 = &Plus::plusd;
    Plus pd;
    cout << f5(&pd, 1.1, 1.1) << endl;
    
    // 使用bind简化成员函数调用
    function<double(double, double)> f6 = bind(&Plus::plusd, Plus(), placeholders::_1, placeholders::_2);
    cout << f6(1.1, 1.1) << endl;
    
    return 0;
}

逆波兰表达式求值

cpp 复制代码
#include<stack>
#include<map>
#include<functional>
#include<vector>
#include<string>
using namespace std;

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        
        // 使用map映射操作符和对应的可调用对象
        map<string, function<int(int, int)>> opFuncMap = {
            {"+", [](int x, int y) { return x + y; }},
            {"-", [](int x, int y) { return x - y; }},
            {"*", [](int x, int y) { return x * y; }},
            {"/", [](int x, int y) { return x / y; }}
        };
        
        for(auto& str : tokens) {
            if(opFuncMap.count(str)) {  // 操作符
                int right = st.top(); st.pop();
                int left = st.top(); st.pop();
                int ret = opFuncMap[str](left, right);
                st.push(ret);
            } else {  // 操作数
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};

6.2 bind

std::bind用于创建新的可调用对象,可以调整参数顺序和个数。

cpp 复制代码
#include<functional>
using namespace std::placeholders;  // 用于_1, _2, _3...

int Sub(int a, int b) { return (a - b) * 10; }
int SubX(int a, int b, int c) { return (a - b - c) * 10; }

class Plus {
public:
    double plusd(double a, double b) { return a + b; }
};

int main()
{
    // 基本绑定
    auto sub1 = bind(Sub, _1, _2);
    cout << sub1(10, 5) << endl;  // 输出:50
    
    // 调整参数顺序
    auto sub2 = bind(Sub, _2, _1);
    cout << sub2(10, 5) << endl;  // 输出:-50
    
    // 绑死部分参数
    auto sub3 = bind(Sub, 100, _1);
    cout << sub3(5) << endl;      // 输出:950
    
    // 多参数函数的绑定
    auto sub5 = bind(SubX, 100, _1, _2);
    cout << sub5(5, 1) << endl;   // 输出:940
    
    // 绑定成员函数
    function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
    cout << f7(1.1, 1.1) << endl;
    
    // 实际应用:计算复利
    auto func1 = [](double rate, double money, int year)->double {
        double ret = money;
        for (int i = 0; i < year; i++) {
            ret += ret * rate;
        }
        return ret - money;
    };
    
    // 绑死利率和年限,创建不同投资方案的计算器
    function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);
    function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5);
    
    cout << func3_1_5(1000000) << endl;  // 3年期1.5%利率的利息
    cout << func5_1_5(1000000) << endl;  // 5年期1.5%利率的利息
    
    return 0;
}

七、总结

主要特性回顾

  1. 列表初始化 :统一的初始化语法,支持一切对象使用{}初始化
  2. 可变参数模板:支持类型和数量可变的模板参数,为泛型编程带来极大灵活性
  3. 新的类功能
    • 默认移动操作
    • 成员变量缺省值
    • default/delete控制函数生成
  4. lambda表达式:简洁的匿名函数,替代复杂的函数对象
  5. 包装器
    • function:统一可调用对象类型
    • bind:参数绑定和适配

实际开发建议

  1. 优先使用现代C++特性

    cpp 复制代码
    // 推荐
    vector<int> v{1, 2, 3, 4, 5};
    auto lambda = [](auto x) { return x * 2; };
    function<int(int)> f = lambda;
    
    // 而不是传统方式
    vector<int> v;
    v.push_back(1); v.push_back(2); // ...
  2. 利用emplace系列接口

    cpp 复制代码
    vector<complex_type> vec;
    vec.emplace_back(arg1, arg2);  // 直接构造,避免拷贝
  3. 善用lambda简化代码

    cpp 复制代码
    // 替代复杂的仿函数
    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {
        return a.value < b.value;
    });
  4. 使用function统一回调接口:

    cpp 复制代码
     // 定义统一的回调接口
     class EventHandler {
     private:
         function<void(int, const string&)> callback_;
     
     public:
         void setCallback(function<void(int, const string&)> cb) {
             callback_ = move(cb);
         }
     
         void triggerEvent(int id, const string& msg) {
             if (callback_) {
                 callback_(id, msg);
             }
         }
     };
     
     // 使用lambda作为回调
     EventHandler handler;
     handler.setCallback([](int id, const string& msg) {
         cout << "Event " << id << ": " << msg << endl;
     });
     
     // 也可以使用普通函数
     void logEvent(int id, const string& msg) {
         cout << "Log: Event " << id << " - " << msg << endl;
     }
     handler.setCallback(logEvent);
     
     // 或者使用成员函数
     class Logger {
     public:
         void memberCallback(int id, const string& msg) {
             cout << "Member: Event " << id << " - " << msg << endl;
         }
     };
     
     Logger logger;
     handler.setCallback(bind(&Logger::memberCallback, &logger, 
                             placeholders::_1, placeholders::_2));
相关推荐
2501_941111332 小时前
C++代码重构实战
开发语言·c++·算法
爱装代码的小瓶子2 小时前
【c++知识铺子】相对简单的容器适配器双生子-stack和queue(STL)
开发语言·c++
豐儀麟阁贵2 小时前
6.2 Object类
java·开发语言·python
MichaelIp2 小时前
Python同步vs异步性能对比实验-2
开发语言·python·性能优化·可用性测试
white-persist2 小时前
二进制movl及CTF逆向GDB解析:Python(env)环境下dbg从原理到实战
linux·服务器·开发语言·python·网络安全·信息可视化·系统安全
脏脏a2 小时前
类和对象(下):初始化列表、静态成员与友元深度解析
开发语言·c++
lkbhua莱克瓦242 小时前
Java进阶——集合进阶(MAP)
java·开发语言·笔记·github·学习方法·map
代码狂想家2 小时前
Rust 命令行密码管理器工具开发
开发语言·rust·php