『 C++11 』模板可变参数包,Lambda表达式与 function 包装器

news2024/11/15 8:33:57

文章目录

    • 模板可变参数模板
      • 可变参数包的展开
      • 可变参数包与STL容器中的emplace函数关系
    • Lambda 表达式
    • function 包装器
      • function 包装器对成员函数的包装
      • bind 绑定


模板可变参数模板

请添加图片描述

可变参数模板是C++11引入的一个特性,允许模板接收任意数量的参数;

该特性增加了C++的泛型编程能力;

可变参数模板引入可使用...来表示模板参数包;

可在模板参数和函数参数中使用;

template<class ...Args>
void func(Args ...args)

其中class ...Args表示其可变参数包的类型名为Args;

func()函数中的Args ...args表示传入一个该可变参数包;

template <class ...Args>
void func1(Args ...args){
 // 代码
}

int main() {
  func1(1, "666", 'a', 2.2);
  return 0;
}
  • 可变参数包的参数类型个数

    可通过sizeof()来查看当前传入的可变参数包的参数类型个数;

    template <class... Args>
    void func1(Args... args) {
      cout << sizeof...(args) << endl;
    }
    
    int main() {
      func1(1, "666", 'a', 2.2);
      return 0;
    }
    

    通常在使用sizeof()对可变参数包的参数个数进行查看时语法规定必须使用sizeof...(可变参数包)进行查看;

    运行结果为:

    $ ./test 
    4
    

可变参数包的展开

请添加图片描述

可变参数包通常使用...展开参数包,如:

func(args...);

当编译器遇到args...时会将参数包中的每个参数都展开为独立的参数;

假设传入func()函数的参数为'c',10,2.2时,在函数func中将优先获取第一个参数c;

其参数展开的顺序按照它们在参数包中的顺序;

通常展开参数包的方法以递归,或是利用初始化数组使其进行展开;

  • 递归方式展开

    void _ShowList() { cout << endl; }
    
    template <class T, class... Args>
    void _ShowList(const T& t1, Args... args) {
      cout << typeid(t1).name() << " : " << t1 << endl; // 打印参数类型与参数值
      _ShowList(args...);
    }
    
    template <class... Args>
    void ShowList(Args... args) {
      _ShowList(args...);
    }
    
    int main() {
      ShowList(1, "666", 'a', 2.2);
      return 0;
    }
    

    在这个例子中ShowList()函数是一个使用模板可变参数包的函数模板;

    _ShowList()函数则是该函数的子函数,该函数将一个可变参数包衍生为一个T类型的模板参数与一个可变参数包class ...Args,并且该函数存在一个返回值与参数都为空的函数;

    调用ShowList()函数并传入1, "666", 'a', 2.2为参数;

    根据可变参数包的展开原理,_ShowList()中的const T&类型将优先获取可变参数包中的第一个参数,并将剩余的可变参数包以递归的形式调用逐个进行展开,当可变参数包中所有参数被展开完毕后将对应的调用无参的_ShowList()函数重载;

    运行结果为:

    $ ./test 
    i : 1
    PKc : 666
    c : a
    d : 2.2
    
  • 初始化数组形式展开

    template <class T>
    int _Analysis(T t) {
      cout << t << endl;
      return 0;
    }
    
    template <class... Args>
    void Analysis(Args... args) {
      int arr[] = {_Analysis(args)...};
    }
    
    int main() {
      Analysis(1, "666", 'a', 2.2);
      return 0;
    }
    

    在这个例子中定义了一个可变模板参数包函数模板Analysis(),并定义了一个模板参数类型为T的子函数模板_Analysis();

    传入参数并调用Analysis()函数,其将接收到这个可变参数包,并将其对数组进行初始化;

    此处的初始化采用列表初始化对数组进行初始化,在列表初始化中将根据可变参数包的数据个数依次调用_Analysis()函数并传入对应的可变参数包,最终实现可变参数包的展开;

    对应其展开时将会把int arr[] = {_Analysis(args)...}展开为:

    int arr[] = {_Analysis(1), _Analysis("666"), _Analysis('a'), _Analysis(2.2)};
    

    运行结果为:

    $ ./test 
    1
    666
    a
    2.2
    

可变参数包与STL容器中的emplace函数关系

请添加图片描述

在 C++11 中对容器更新了对应的emplace版本的函数;

std::vector<>std::list<>中的emplace_back:

// vector
template <class... Args>  void emplace_back (Args&&... args);

// list
template <class... Args>  void emplace_back (Args&&... args);

其中可变参数包允许函数接收任意数量和类型的参数,使得emplace_back可以直接接收构造新元素所需的所有参数;

  • 万能引用

    其中函数调用中使用了万能引用Args&&... args使得函数既可以接收左值夜可以接收右值;

其中该函数的实现依靠了完美转发,使得其可以通过std::forward<Args>(args)...保持可变参数包原有的属性将其转发至真正构造的部分,即直接在分配的内存上构造函数从而不需要再使用移动或拷贝构造,而是直接构造;

该函数的实现对于传递右值时与普通插入函数没有太大的差异,对于右值而言普通插入函数可通过移动构造的方式,即 构造+移动 ;

移动语义的开销本身就不是特别大,故emplace版本插入函数与传右值时的普通插入函数效率大差不差,但在使用普通插入函数传递左值进行构造时无法进行移动语义,如移动构造或是移动赋值,此时必将调用对应的拷贝构造函数进行深拷贝;

emplace版本插入函数可通过直接传递其可变参数包使得直接将参数在分配的内存空间上直接构造;

从而避免了拷贝构造的开销;


Lambda 表达式

请添加图片描述

lambda表达式是C++ 11 引入的一个新的特性,允许创建匿名函数对象;

Lambda表达式提供一种较为简洁的方式定义行内函数,通常适用于需要短小函数的场景,如算法库中的回调函数;

[capture](parameters) mutable -> return_type { body }
  • [capture]捕获列表

    捕获列表定义了Lambda表达式可以访问的外部作用域中的变量,其中该外部作用域指的是Lambda表达式外部的作用域;

    其语法为:

    • []

      表示不捕获任何外部变量;

    • [=]

      表示以传值的方式捕获所有外部变量;

      通常以传值的方式捕获的变量在Lambda表达式中不允许被修改(与mutable有关,mutable为可选项,不使用mutableLambda中的参数带const属性);

      当该Lambda为类内成员函数中的行内函数时,该方式可以传值的方式获取该类的this指针(表示可直接以传值的方式访问该类内成员);

    • [&]

      表示以引用方式捕获所有外部变量;

      通常以传引用的方式捕获的变量可在Lambda表达式中被修改,且与引用相同,同时在使用[&]时可不需要声明mutable;

      当该Lambda为类内成员函数中的行内函数时,使用[&]为默认捕获时对this指针依旧是传值捕获,这是一个特殊的捕获处理;

    • [x,&y]

      捕获列表可同时以不同的捕获方式或相同的捕获方式捕获多个特定的外部变量,但在捕获时不可重复以同一种方式捕获,如[x,&x],[=,x][=,&]等;

    • [this]

      表示以传值捕获的方式捕获当前类的this指针;

    • [=,&x]

      表示以传值方式捕获所有外部变量,但对x以传引用捕获方式捕获;

  • (parameters)参数列表

    参数列表与普通函数类似,可指定参数的类型与名称;

    参数列表定义了Lambda表达式接收的输入参数;

    对应的如果Lambda没有参数可以省略()或使用()或在参数列表中传入void;

  • mutable关键字

    该关键字允许在Lambda表达式内部修改通过传值捕获的变量;

    通常传值捕获的变量具有const属性,具有const属性的变量无法被修改,而使用mutable关键字进行修饰后则可以修改通过传值捕获的参数;

  • -> return_type

    Lambda表达式可以显示指定该表达式返回的类型;

    通常该类型可直接省略,让编译器自动推导;

  • { body }

    Lambda表达式的函数体是包含在花括号{}内的代码块,用来定义Lambda表达式的行为;

    该函数体与普通函数的函数体非常相似;

    在函数体内可以使用捕获列表捕获的变量,当该Lambda表达式不存在返回值时可不使用returnLamdba表达式进行返回;

Lambda表达式本质上是一个仿函数,其底层的实现就是依靠仿函数,将先为该函数实例化出一个对象,再调用其对应的operator()()运算符重载;

通常使用auto接收Lambda表达式所实例化的匿名函数对象,在WindowsLambda表达式其函数名是一个以lambda_uuid进行命名的一个仿函数(不同的系统对应命名的方式也不同);

int main() {
  auto f1 = []() { cout << "hello world" << endl; };
  f1();
  cout << typeid(f1).name() << endl;
  return 0;
}

在这个例子中使用Lambda表达式创建了一个匿名函数对象,并用f1,进行接收,同时打印出对应Lambda表达式的类型名,省略了返回值类型与mutable关键字,运行结果为;

# 此处以 Linux 做测试

$ ./test 
hello world
Z4mainEUlvE_
  • Lambda 表达式的使用

    int main() {
      int a = 10;
      int b = 20;
    
      // f1: 值捕获 a 和 b,只读访问
      auto f1 = [=]() { cout << a << " : " << b << endl; };
      f1();  // 输出: 10 : 20
    
      // f2: 引用捕获所有变量,可以修改 a 和 b
      auto f2 = [&]() {
        int tmp = a;
        a = b;
        b = tmp;
      };
      f2();
      cout << a << " : " << b << endl;  // 输出: 20 : 10 (a 和 b 的值被交换)
    
      // f3: 值捕获 a 和 b,使用 mutable 允许修改捕获的副本,但不影响原始变量
      auto f3 = [a, b]() mutable {
        int tmp = a;
        a = b;
        b = tmp;
      };
      f3();
      cout << a << " : " << b << endl;  // 输出: 20 : 10 (原始 a 和 b 不变)
    
      // f4: 值捕获 a,引用捕获 b,mutable 允许修改 a 的副本和 b 的原始值
      auto f4 = [a, &b]() mutable {
        int tmp = a;
        a = b;
        b = tmp;
      };
      f4();
      cout << a << " : " << b << endl;  // 输出: 20 : 20 (只有 b 被修改为 a 的初始值)
    
      b = 5;  // 修改 b 的值
      // f5: 引用捕获 a 和 b,可以直接修改原始变量
      auto f5 = [&a, &b]() {
        int tmp = a;
        a = b;
        b = tmp;
      };
      f5();
      cout << a << " : " << b << endl;  // 输出: 5 : 20 (a 和 b 的值再次交换)
    
      // f6: 通过参数引用直接操作传入的变量
      auto f6 = [](int& x, int& y) {
        int tmp = x;
        x = y;
        y = tmp;
      };
      f6(a, b);
    
      cout << a << " : " << b << endl;  // 输出: 20 : 5 (a 和 b 的值再次交换)
    
      return 0;
    }
    
    

    这个例子展示了Lambda表达式的不同捕获方式和他们对变量的影响;

    其运行结果为(参考代码与注释):

    $ ./test 
    10 : 20
    20 : 10
    20 : 10
    20 : 20
    5 : 20
    20 : 5
    

    同时Lambda表达式可不使用auto接收并直接使用,如:

    int main() {
      int a = 10;
      int b = 20;
    
      [=]() { cout << a << " : " << b << endl; }(); /* 实例化匿名函数对象后直接使用()进行调用 */
      
      int i = [=]() { cout << a << " : " << b << endl;return 10; }(); /* 也可在实例化匿名函数对象使用()调用后对其返回值进行接收 */
    
      return 0;
    }
    

Lambda表达式的捕获列表[]只可捕获其父作用域中的变量;

  • Lambda表达式之间不可相互赋值

    Lambda表达式之间不可相互赋值,本质原因是虽然其为一个匿名函数对象,但其在底层有其相应的命名方式,每个Lambda表达式的命名在底层是不同的,故其类型也不相同,无法相互赋值;


function 包装器

请添加图片描述

std::function函数包装器是C++11引入的一个用于存储,复制和调用任何可调用目标的一个包装器;

其可以存储,复制和调用的对象包括:

  • 普通函数
  • 函数指针
  • Lambda表达式
  • 绑定表达式
  • 函数对象(实现了operator()的类的对象,即仿函数)

基本语法为:

std::function<返回类型(参数类型列表)> 函数对象名;

以下列代码为例:

#include <iostream>
#include <functional>
using namespace std;

// 定义一个普通的全局函数
void Print() { cout << "Hello Print" << endl; }

// 定义一个函数对象(仿函数)类
class Functor {
 public:
  // 重载 operator() 使得该类的对象可以像函数一样被调用
  void operator()() { cout << "Hello Functor" << endl; }
};

int main() {
  // 定义一个 lambda 表达式
  auto func1 = []() { cout << "Hello Func1" << endl; };

  // 使用 std::function 创建函数包装器
  // f1 包装普通函数 Print
  function<void()> f1 = Print;
  
  // f2 包装 Functor 类的实例(函数对象)
  function<void()> f2 = Functor();
  
  // f3 包装 lambda 表达式 func1
  function<void()> f3 = func1;

  // 通过统一的接口调用这些不同类型的可调用对象
  f1();  // 输出: Hello Print
  f2();  // 输出: Hello Functor
  f3();  // 输出: Hello Func1

  return 0;
}

其运行结果为:

$ ./test 
Hello Print
Hello Functor
Hello Func1

function 包装器对成员函数的包装

请添加图片描述

function包装器对成员函数的包装与普通函数的包装不同;

成员函数隐含了一个this指针,通常在使用function包装器对成员函数包装时通常要为成员函数加上 域作用限定符::&;

  • 对静态成员函数

    使用function包装器对静态成员函数而言其不存在对应的this指针,可直接进行包装;

    但为了与普通函数或Lambda表达式的包装进行区分也应使用&进行区分;

    #include <iostream>
    #include <functional>
    
    // 定义一个测试类 TestClass
    class TestClass {
     public:
      // 定义一个静态成员函数 func1
      // 静态成员函数不需要类的实例就可以调用
      // 参数: 两个整数 x 和 y
      // 返回值: 整数 (x + y)
      static int func1(int x, int y) {
        printf("func 1 ,x: %d , y: %d \n", x, y);  // 打印输入的参数
        return x + y;  // 返回两个参数的和
      }
    };
    
    int main() {
      // 创建一个 std::function 对象 f1
      // 它可以存储任何返回 int 并接受两个 int 参数的可调用对象
      // 这里我们将静态成员函数 TestClass::func1 的地址赋值给 f1
      std::function<int(int, int)> f1 = &TestClass::func1;
    
      // 调用 f1,传入参数 10 和 20
      // f1 会调用 TestClass::func1(10, 20)
      // 然后打印返回值
      std::cout << f1(10, 20) << std::endl;
    
      return 0;  // 程序正常结束
    }
    
  • 对非静态成员函数的包装

    非静态成员函数,即普通成员函数中默认存在一个隐含的this指针;

    对于静态成员函数的包装而言相同,都需要加上&与域作用限定符::;

    同时其需要传入一个该类类型的指针,否则参数将不匹配;

    #include <iostream>
    #include <functional>
    
    // 定义一个测试类 TestClass
    class TestClass {
     public:
      // 定义一个非静态成员函数 func2
      // 非静态成员函数需要通过类的实例来调用
      // 参数: 两个双精度浮点数 x 和 y
      // 返回值: 双精度浮点数 (x + y)
      double func2(double x, double y) {
        printf("func 2 ,x: %.1f , y: %.1f \n", x, y);  // 打印输入的参数,保留一位小数
        return x + y;  // 返回两个参数的和
      }
    };
    
    int main() {
      // 创建一个 std::function 对象 f2
      // 它可以存储任何返回 double 并接受 TestClass* 和两个 double 参数的可调用对象
      // 这里我们将非静态成员函数 TestClass::func2 的地址赋值给 f2
      std::function<double(TestClass*, double, double)> f2 = &TestClass::func2;
    
      // 创建 TestClass 的一个实例 t
      TestClass t;
    
      // 调用 f2,传入 &t(TestClass 实例的地址)和参数 1.1, 2.2
      // f2 会调用 t.func2(1.1, 2.2)
      // 然后打印返回值
      std::cout << f2(&t, 1.1, 2.2) << std::endl;
    
      return 0;  // 程序正常结束
    }
    

    此处不能直接实例化匿名对象进行传入,匿名对象是一个临时对象,为右值,右值无法被取地址&;

两段代码结合测试并运行:

#include <iostream>
#include <functional>

// 定义一个测试类 TestClass
class TestClass {
 public:
  // 定义一个静态成员函数 func1
  // 静态成员函数不需要类的实例就可以调用
  // 参数: 两个整数 x 和 y
  // 返回值: 整数 (x + y)
  static int func1(int x, int y) {
    printf("func 1 ,x: %d , y: %d \n", x, y);  // 打印输入的参数
    return x + y;  // 返回两个参数的和
  }

  // 定义一个非静态成员函数 func2
  // 非静态成员函数需要通过类的实例来调用
  // 参数: 两个双精度浮点数 x 和 y
  // 返回值: 双精度浮点数 (x + y)
  double func2(double x, double y) {
    printf("func 2 ,x: %.1f , y: %.1f \n", x, y);  // 打印输入的参数,保留一位小数
    return x + y;  // 返回两个参数的和
  }
};

int main() {
  // 创建一个 std::function 对象 f1
  // 它可以存储任何返回 int 并接受两个 int 参数的可调用对象
  // 这里我们将静态成员函数 TestClass::func1 的地址赋值给 f1
  std::function<int(int, int)> f1 = &TestClass::func1;

  // 调用 f1,传入参数 10 和 20
  // f1 会调用 TestClass::func1(10, 20)
  // 然后打印返回值
  std::cout << f1(10, 20) << std::endl;

  // 创建一个 std::function 对象 f2
  // 它可以存储任何返回 double 并接受 TestClass* 和两个 double 参数的可调用对象
  // 这里我们将非静态成员函数 TestClass::func2 的地址赋值给 f2
  std::function<double(TestClass*, double, double)> f2 = &TestClass::func2;

  // 创建 TestClass 的一个实例 t
  TestClass t;

  // 调用 f2,传入 &t(TestClass 实例的地址)和参数 1.1, 2.2
  // f2 会调用 t.func2(1.1, 2.2)
  // 然后打印返回值
  std::cout << f2(&t, 1.1, 2.2) << std::endl;

  return 0;  // 程序正常结束
}

运行结果为:

$ ./test 
func 2 ,x: 10 , y: 20 
30
func 1 ,x: 1.1 , y: 2.2 
3.3

bind 绑定

请添加图片描述

bind是C++11引入的一个函数模板;

该函数模板用于将函数和某些参数进行绑定创建一个新的可调用对象;

这个函数的对象可以不立即调用,同时其可以将部分或全部参数与函数进行绑定;

其基本语法为:

auto newCallable = std::bind(callable, arg1, arg2, ...);
  • callable

    该参数为任何可调用对象,如函数指针,成员函数指针,Lambda表达式,function包装后的可调用对象,仿函数等;

其可以绑定任意数量的参数,通常使用std::placeholders:: _1 , _2 , _3来表示未绑定的参数;

同时bind可改变原函数参数的顺序;

// 定义一个减法函数
int Sub(int a, int b) { return a - b; }

// 定义一个除法结构体,使用函数调用运算符
struct Div {
  int operator()(int a, int b) { return a / b; }
};

int main() {
  // 定义一个取模的 lambda 函数
  auto Mod = [](int a, int b) { return a % b; };

  // 绑定 Sub 函数,保持参数顺序不变
  auto sub1 = bind(Sub, placeholders::_1, placeholders::_2);
  cout << sub1(10, 20) << endl;  // 输出 -10 (10 - 20)

  // 绑定 Sub 函数,交换参数顺序
  auto sub2 = bind(Sub, placeholders::_2, placeholders::_1);
  cout << sub2(10, 20) << endl;  // 输出 10 (20 - 10)

  // 绑定 Div 函数对象,固定第二个参数为 2
  auto div1 = bind(Div(), placeholders::_1, 2);
  cout << div1(100) << endl;  // 输出 50 (100 / 2)

  // 绑定 Div 函数对象,固定第一个参数为 10
  auto div2 = bind(Div(), 10, placeholders ::_1);
  cout << div2(2) << endl;  // 输出 5 (10 / 2)

  // 绑定 Mod lambda 函数,固定两个参数
  auto mod1 = bind(Mod, 11, 10);
  cout << mod1() << endl;  // 输出 1 (11 % 10)

  return 0;
}

在这个例子中:

  • sub1

    简单绑定了一个函数,保持参数顺序不变;

  • sub2

    绑定了一个函数,但交换了参数的顺序;

  • div1

    绑定了一个函数对象(Div仿函数)并固定第二个参数;

  • div2

    绑定了一个仿函数并固定第一个参数;

  • mod1

    绑定了一个Lambda表达式实例化的函数,并固定所有参数;

运行结果如下:

$ ./test 
-10
10
50
5
1

在使用function包装器对类内非静态成员函数包装时需要传入一个该类类型的指针类型(隐含this指针);

同时在调用该function包装后的非静态成员函数时需要传入一个对应的该类对象指针,在这种情况下可使用bind绑定第一个this指针从而减少调用参数;

class TestClass {
 public:
  // 定义一个成员函数,接受两个double参数并返回它们的和
  double func(double x, double y) {
    printf("func ,x: %.1f , y: %.1f \n", x, y);
    return x + y;
  }
};

int main() {
  // 声明一个 std::function 对象 f2
  // 它表示一个接受 TestClass* 和两个 double 参数,返回 double 的函数
  // 这里绑定了 TestClass::func 成员函数
  function<double(TestClass*, double, double)> f2 = &TestClass::func;

  // 创建 TestClass 的实例
  TestClass t;

  // 使用 std::bind 创建一个新的可调用对象 testfunc
  // 绑定 f2(即 TestClass::func)到 TestClass 实例 t
  // placeholders::_1 和 _2 表示 testfunc 将接受两个参数
  auto testfunc = bind(f2, &t, placeholders::_1, placeholders::_2);

  // 调用 testfunc,传入 1.1 和 2.2 作为参数
  // 这相当于调用 t.func(1.1, 2.2)
  cout << testfunc(1.1, 2.2) << endl;

  return 0;
}

在这个例子中:

function<double(TestClass*, double, double)> f2 = &TestClass::func;

创建了一个function对象以存储TestClass::func的指针;

其中第一个参数必须为TestClass*(该类的this指针类型);

auto testfunc = bind(f2, &t, placeholders::_1, placeholders::_2);

使用了bind创建一个新的可调用对象名为testfunc;

并创建了一个TestClass对象t,并将该对象取地址&绑定在新的可调用对象testfunc的第一个参数上;

默认placeholders::_1, placeholders::_2传递两个参数;

最后调用绑定后的函数并传入1.12.2作为参数;

执行结果为:

$ ./test 
func ,x: 1.1 , y: 2.2 
3.3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1975915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搭建jenkins一键部署java项目

一、搭建jenkins 链接: https://pan.baidu.com/s/1jzx15PiyI8EhLd_vg7q8bw 提取码: ydhl 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 直接使用docker导入镜像&#xff0c;运行就好 docker run -di --name jenkins -p 8080:8080 -v /home/jenkins_home:/var/je…

黑神话:悟空

《黑神话&#xff1a;悟空》是由游戏科学公司制作的以中国神话为背景的动作角色扮演游戏&#xff0c;将于2024年8月20日发售 [9] [14]&#xff0c;简体中文PC标准版售价268人民币,数字豪华版售价328人民币。 [27] [34] 游戏中&#xff0c;玩家将扮演一位“天命人”&#xff0c…

洗袜子的小洗衣机哪款好?小户型洗衣机推荐!懒人洗袜子神器分享

市面上的那些迷你的小型洗衣机可以洗袜子&#xff0c;洗涤空间够一次性洗5-6双左右的袜子&#xff01;这种不仅不会因为清洗的衣物数量少而浪费水浪费电&#xff0c;同时使用也很便利&#xff0c;小小个的放在家的任意角落就可以进行清洗&#xff0c;不仅是清洗袜子这些&#x…

jquery.ajax + antd.Upload.customRequest文件上传进度

前情提要&#xff1a;大文件分片上传&#xff0c;需要利用Upload的customRequest属性自定义上传方法。也就是无法通过给Upload的action属性赋值上传地址进行上传&#xff0c;所以Upload组件自带的上传进度条&#xff0c;也没法直接用了&#xff0c;需要在customRequest中加工一…

GraphSAGE (SAmple and aggreGatE)知识总结

1.前置知识 inductive和transductive 模型训练&#xff1a; Transductive learning在训练过程中已经用到测试集数据&#xff08;不带标签&#xff09;中的信息&#xff0c;而Inductive learning仅仅只用到训练集中数据的信息。 模型预测&#xff1a; Transductive learning只能…

6.前端怎么做一个验证码和JWT,使用mockjs模拟后端

流程图 创建一个发起请求 创建一个方法 getCaptchaImg() {this.$axios.get(/captcha).then(res > {console.log(res);this.loginForm.token res.data.data.tokenthis.captchaImg res.data.data.captchaImgconsole.log(this.captchaImg)})}, captchaImg: "", 创…

【数据结构】排序基本概念、插入排序、希尔排序(详解)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构、LeetCode专栏 &#x1f4da;本系…

java学习--泛型

前言 当我们将dog类放入集合List中想要遍历通过一下手段可实现遍历名字和年龄&#xff0c;但是当我们要加入一个新的Cat类时&#xff0c;他并不会报错&#xff0c;只有编译了才会报错&#xff0c;因为在这一步的时候注定了只能是Dog类&#xff0c;但这是非常不方便的 此时我们…

哦吼,新模型?文生图领域的新模型FLUX.1(附模型下载网盘地址和详细使用方法)

&#x1f3a1;背景 Black Forest Labs 是由 Stable Diffusion 原班人马成立的公司&#xff0c;致力于研发优质的多模态模型并开源。该公司由多位前 Stability AI 研究员组成&#xff0c;包括 Robin Rombach 在内的团队成员&#xff0c;他们在图像和视频生成领域有着杰出的贡献…

取消订单业务

文章目录 概要整体架构流程技术细节小结 概要 取消订单是电子商务、外卖平台、在线零售等多个行业中常见的业务需求之一。这项功能允许消费者或商家取消已下的订单&#xff0c;通常是因为各种原因&#xff08;如商品缺货、配送问题、支付问题等&#xff09;。 需求分析以及接…

【课程总结】day19(中):Transformer架构及注意力机制了解

前言 本章内容&#xff0c;我们将从注意力的基础概念入手&#xff0c;结合Transformer架构&#xff0c;由宏观理解其运行流程&#xff0c;然后逐步深入了解多头注意力、多头掩码注意力、融合注意力等概念及作用。 注意力机制&#xff08;Attension&#xff09; 背景 深度学…

如何在立创EDA的PCB电路板导入logo图案

1、首先制作好logo图案&#xff0c;一般为公司logo图标&#xff0c;如下图 2、打开立创EDA的PCB文件&#xff0c;如下图 3、将PCB的图层切换到丝印层&#xff1a; 4、然后选择EDA菜单栏的放置---图片&#xff1a; 5、进入后点击选择图片&#xff0c;将logo图片导入&#xff0c;…

人生低谷来撸C#--022 winfrom 和WPF

1、简单介绍 标题其实是写错了&#xff0c;是winform,不是winfrom&#xff0c;如果再准确点&#xff0c;应该是 WinForms&#xff08;复数形式&#xff09;&#xff0c;它代表的是 Windows Forms 技术&#xff0c;用于在 .NET Framework 中创建桌面应用程序的用户界面。在 Vis…

数据结构——八大排序

一.排序的概念和其应用 1.1排序的概念 排序&#xff1a;排列或排序是将一组数据按照一定的规则或顺序重新组织的过程&#xff0c;数据既可以被组织成递增顺序&#xff08;升序&#xff09;&#xff0c;或者递减顺序&#xff08;降序&#xff09;。稳定性&#xff1a;假定在待…

Prometheus监控的搭建(ansible安装——超详细)

目录 1.各组件功能介绍 2.安装批量部署工具ansbile 3.执行服务器 4.各服务器间做免密 5.下载安装包 5.1Prometheus的下载的下载地址 5.2exporter的下载地址 5.3grafana的下载地址 6.编辑ansible需要的配置文件 7.编写ansible文件 8.验证执行结果 今天和大家分享一下…

网站在线查询工具箱源码分享

终极网络工具系统”(SAAS)&#xff0c;是一款功能强大的PHP脚本在线查询工具。本版集合了超过470种快速且易用的Web工具&#xff0c;为日常任务处理和开发人员提供了极大的便利。作为一款综合性的网络工具系统&#xff0c;66toolkit不仅满足了用户的基本网络需求&#xff0c;更…

Java面试题 -- 为什么重写equals就一定要重写hashcode方法

在回答这个问题之前我们先要了解equals与hascode方法的本质是做什么的 1. equals方法 public boolean equals(Object obj) {return (this obj);}我们可以看到equals在不重写的情况下是使用判断地址值是否相同 所以默认的 equals 的逻辑就是判断的双方是否引用了一个对象&am…

【EI会议征稿】第四届高性能计算与通信工程国际学术会议(HPCCE 2024)

出版出版 【SPIE出版 | 往届会后3个月内完成EI检索】 第四届高性能计算与通信工程国际学术会议(HPCCE 2024) 2024 4th International Conference on High Performance Computing and Communication 第四届高性能计算与通信工程国际学术会议&#xff08;HPCCE 2024&#xf…

使用Chainlit接入通义千问快速实现一个自然语言转sql语言的智能体

文本到 SQL 让我们构建一个简单的应用程序&#xff0c;帮助用户使用自然语言创建 SQL 查询。 最终结果预览 ​ 先决条件 此示例有额外的依赖项。你可以使用以下命令安装它们&#xff1a; pip install chainlit openai​ 导入 应用程序 from openai import AsyncOpenAI…

扩展------零拷贝技术(Mmap,SendFile)

什么是零拷贝 零拷贝&#xff08;Zero-Copy&#xff09;是一种计算机操作技术&#xff0c;旨在减少数据在内存之间的拷贝次数&#xff0c;以提高数据传输的效率和性能。 传统的IO模式&#xff1a; 模拟网络传输数据运行过程&#xff1a; 用户态read()发起系统调用&#xff0c…