当前位置: 首页 > news >正文

突破编程_C++_C++11新特性(tuple)

1 std::tuple 简介

1.1 std::tuple 概述

std::tuple 是一个固定大小的不同类型值的集合,可以看作 std::pair 的泛化,即 std::pair 是 std::tuple 的一个特例,其长度受限为 2。与 C# 中的 tuple 类似,但 std::tuple 的功能更为强大。

当需要将一些数据组合成一个单一的对象,但又不想麻烦地定义一个新的数据结构来表示这些数据时,std::tuple 是一个非常有用的工具。可以将 std::tuple 看作一个“快速而随意”的数据结构。

std::tuple 的一个重要特性是它可以存储不同类型的数据,这是它与常规 STL 容器的最大不同。例如,可以在一个 std::tuple 中同时存储一个整数、一个字符串和一个浮点数。定义 std::tuple 时,需要指出每个成员的类型,如 std::tuple<int, std::string> tu{2, “12iop”};。

访问 std::tuple 中的元素通常使用 std::get<N>() 函数,其中N是元素的索引(从0开始)。例如,如果有一个 std::tuple<int, char> my_tuple,则可以使用std::get<0>(my_tuple) 来获取第一个元素(整数),使用 std::get<1>(my_tuple) 来获取第二个元素(字符)。

1.2 std::tuple 与 std::pair 的区别

std::tuple 和 std::pair 都是 C++ 标准库中的模板类,用于将多个数据项组合成一个单一的复合数据结构。然而,它们在功能、用途以及数据项的数量上存在显著的差异:

(1)数据项数量:

  • std::pair:这是一个特殊的模板类,只能将两个不同类型的数据项绑定成一个对象。也就是说,std::pair只能存储两个元素。
  • std::tuple:相比之下,std::tuple的功能更为强大,它可以绑定任意数量的不同类型的数据项。也就是说,std::tuple的成员数量是没有限制的。

(2)命名和访问方式:

  • std::pair:它为每个元素提供了特定的名字,即 first 和 second,用于访问和操作这两个元素。这种命名方式使得 std::pair 在表示一些具有特定关系的两个数据项时(如坐标点的 x 和 y)非常直观和方便。
  • std::tuple:由于它可以包含任意数量的元素,因此不能为每个元素都提供特定的名字。相反,需要使用 std::get<N>() 函数,其中N是元素的索引(从 0 开始),来访问 std::tuple 中的元素。在 C++17 及以后的版本中,也可以使用结构化绑定(structured binding)来更方便地解包和访问 std::tuple 中的元素。

(3)使用场景:

  • std::pair:由于其只能存储两个元素,并且提供了特定的名字,它通常用于表示具有特定关系的两个数据项,如键值对、坐标点等。
  • std::tuple:由于其可以存储任意数量的元素,且元素类型可以不同,它通常用于需要将多个不同类型的数据项组合在一起的情况。此外,std::tuple 还可以作为函数返回多个值的机制,这在 std::pair 无法满足需求时尤其有用。

1.3 std::tuple 的用途与场景

以下是 std::tuple 的主要用途与场景:

(1)作为函数返回多个值:
场景:当希望一个函数返回多个值时,可以使用 std::tuple 来避免使用全局变量或指针参数传递结果。
用途:通过将多个返回值打包成一个 std::tuple 对象,可以方便地返回多个值,并在调用方进行解包。

(2)存储不同类型的数据项:
场景:当需要存储多个不同类型的数据项,但又不想定义一个新的数据结构时。
用途:std::tuple 可以存储任意数量的不同类型的数据项,提供了一种灵活的方式来组合数据。

(3)在泛型编程中传递参数:
场景:在泛型编程中,可能需要传递多个参数给某个函数或模板,而这些参数的类型可能各不相同。
用途:使用 std::tuple 可以方便地打包这些参数,并通过引用或值的方式传递给其他函数或模板。

(4)与算法结合使用:
场景:在编写算法时,可能需要处理多个不同类型的数据项。
用途:std::tuple 可以作为算法的输入或输出,使得算法能够处理不同类型的数据,并返回多个结果。

(5)替代结构体或类:
场景:当需要临时组合几个数据项,但又不想定义一个完整的结构体或类时。
用途:std::tuple 提供了一种轻量级的方式来组合数据,无需编写额外的结构体或类定义。

(6)与STL容器结合使用:
场景:在需要存储多个 std::tuple 对象的场景中,如集合、映射或向量等。
用途:std::tuple 可以作为 STL 容器的元素类型,使得容器能够存储包含多个不同类型数据项的对象。

(7)作为模板元编程的工具:
场景:在模板元编程中,std::tuple 可以用于类型列表的创建和操作。
用途:通过 std::tuple,可以方便地构建和操作类型列表,实现更复杂的类型操作和元函数。

2 std::tuple 的基本操作

2.1 std::tuple 的创建

最常见的方法是使用 std::make_tuple 函数,它接受任意数量和类型的参数,并返回一个包含这些参数的 std::tuple 对象。

例如:

#include <tuple>  
#include <iostream>  
#include <string>  int main() 
{  // 创建一个包含整数、字符串和浮点数的 tuple  std::tuple<int, std::string, double> myTuple = std::make_tuple(12, "Hello", 3.14);  // 输出 tuple 中的元素  std::cout << "Integer: " << std::get<0>(myTuple) << std::endl;  std::cout << "String: " << std::get<1>(myTuple) << std::endl;  std::cout << "Double: " << std::get<2>(myTuple) << std::endl;  return 0;  
}

这个例子创建了一个包含整数 12、字符串 “Hello” 和浮点数 3.14 的 std::tuple 对象。std::get<N>(tuple) 函数用于访问 tuple 中索引为 N 的元素,其中 N 是从 0 开始的索引。

2.2 std::tuple 的访问与修改

(1)访问 std::tuple 中的元素

访问 std::tuple 中的元素主要使用 std::get 函数。std::get 函数接受两个参数:要访问的元素的索引(从 0 开始)和 tuple 对象本身。它返回对应索引位置的元素的引用,因此你可以读取或修改该元素的值(如果元素不是常量)。

示例:

#include <tuple>  
#include <iostream>  
#include <string>  int main() 
{  std::tuple<int, std::string, double> myTuple = std::make_tuple(12, "Hello", 3.14);  // 访问 tuple 中的元素  int first = std::get<0>(myTuple);     // 获取第一个元素(整数 12)  std::string second = std::get<1>(myTuple); // 获取第二个元素(字符串 "Hello")  double third = std::get<2>(myTuple);      // 获取第三个元素(浮点数 3.14)  // 输出元素的值  std::cout << "First: " << first << std::endl;  std::cout << "Second: " << second << std::endl;  std::cout << "Third: " << third << std::endl;  return 0;  
}

上面的示例使用 std::get<N>(myTuple) 来访问 myTuple 中的每个元素,其中 N 是元素的索引。

(2)修改 std::tuple 中的元素

由于 std::get 返回的是元素的引用,因此可以直接通过它来修改 tuple 中的元素值。注意:不能改变 tuple 的大小或添加/删除元素,只能修改现有元素的值。

示例:

#include <tuple>  
#include <iostream> 
#include <string>   int main() 
{  std::tuple<int, std::string, double> myTuple = std::make_tuple(12, "Hello", 3.14);  // 修改 tuple 中的元素  std::get<0>(myTuple) = 100;             // 修改第一个元素为整数 100  std::get<1>(myTuple) = "World";         // 修改第二个元素为字符串 "World"  std::get<2>(myTuple) = 2.1;           // 修改第三个元素为浮点数 2.1  // 输出修改后的元素值  std::cout << "Modified First: " << std::get<0>(myTuple) << std::endl;  std::cout << "Modified Second: " << std::get<1>(myTuple) << std::endl;  std::cout << "Modified Third: " << std::get<2>(myTuple) << std::endl;  return 0;  
}

这个示例使用 std::get<N>(myTuple) 来获取元素的引用,并直接赋值以修改元素的值。

2.3 std::tuple 的大小与类型

std::tuple 的大小和类型在创建时就已经确定,并且在整个生命周期中保持不变。为了获取 std::tuple 的大小和类型信息,C++ 标准库提供了 std::tuple_size 和 std::tuple_element 这两个模板类。通过使用 std::tuple_size 和 std::tuple_element,可以在编译时获取 std::tuple 的大小和类型信息,这对于编写泛型代码和进行元编程非常有用。

(1)使用 std::tuple_size 获取大小

std::tuple_size 是一个模板类,它用于在编译时获取 std::tuple 的大小(即元素数量)。这个模板类接受一个 tuple 类型作为模板参数,并定义了一个名为 value 的静态成员常量,表示该 tuple 的大小。

下面是一个使用 std::tuple_size 获取 tuple 大小的示例:

#include <tuple>  
#include <iostream>  int main() 
{  std::tuple<int, double, std::string> myTuple;  // 使用 std::tuple_size 获取 tuple 的大小  constexpr std::size_t tupleSize = std::tuple_size<decltype(myTuple)>::value;  std::cout << "Tuple size: " << tupleSize << std::endl; // 输出: Tuple size: 3  return 0;  
}

这个示例创建了一个包含三个元素的 tuple(一个 int、一个 double 和一个 std::string)。然后,使用 std::tuple_size 来获取这个 tuple 的大小,并将其存储在 tupleSize 变量中。注意,std::tuple_size 是一个模板类,因此需要使用 decltype 来获取 myTuple 的类型,并将其作为模板参数传递给 std::tuple_size。最后,通过访问 std::tuple_size<decltype(myTuple)>::value 来获取 tuple 的大小。

(2)使用 std::tuple_element 获取类型

std::tuple_element 是一个模板类,它用于在编译时获取 std::tuple 中指定位置的元素的类型。这个模板类接受两个模板参数:第一个参数是元素的索引(从 0 开始),第二个参数是 tuple 的类型。它定义了一个名为 type 的嵌套类型别名,表示该索引位置的元素的类型。

下面是一个使用 std::tuple_element 获取 tuple 中元素类型的示例:

#include <tuple>  
#include <iostream>  
#include <type_traits>  int main() 
{  std::tuple<int, double, std::string> myTuple;  // 使用 std::tuple_element 获取 tuple 中指定位置元素的类型  using FirstElementType = std::tuple_element<0, decltype(myTuple)>::type;  using SecondElementType = std::tuple_element<1, decltype(myTuple)>::type;  using ThirdElementType = std::tuple_element<2, decltype(myTuple)>::type;  std::cout << "First element type: " << typeid(FirstElementType).name() << std::endl; // 输出类型名,可能是 "i" 对于 int  std::cout << "Second element type: " << typeid(SecondElementType).name() << std::endl; // 输出类型名,可能是 "d" 对于 double  std::cout << "Third element type: " << typeid(ThirdElementType).name() << std::endl; // 输出类型名,可能是与 std::string 相关的复杂类型名  return 0;  
}

这个示例使用 std::tuple_element 来获取 tuple 中每个位置的元素的类型,并将它们存储在类型别名 FirstElementType、SecondElementType 和 ThirdElementType 中。然后,使用 typeid 运算符和 name 成员函数来获取这些类型的名称,并输出它们。注意,typeid 和 name 通常用于调试目的,因为返回的类型名称可能是编译器特定的,并且可能不容易阅读。在实际编程中,通常不需要直接打印类型名称,而是依赖于类型推导和模板机制来处理 tuple 中的元素类型。

3 std::tuple 的高级特性

3.1 std::tuple 的赋值与拷贝

(1)赋值操作

std::tuple 的赋值操作可以通过使用 = 运算符来完成。可以将一个 tuple 的值赋给另一个同类型的 tuple。在赋值过程中,源 tuple 中的每个元素都会被复制到目标 tuple 中对应的位置。

下面是一个简单的示例,展示了如何进行 std::tuple 的赋值操作:

#include <tuple>  
#include <iostream>  
#include <string>   int main() 
{  // 创建并初始化第一个 tuple  std::tuple<int, double, std::string> tuple1(1, 2.0, "three");  // 创建第二个未初始化的 tuple,与 tuple1 类型相同  std::tuple<int, double, std::string> tuple2;  // 将 tuple1 的值赋给 tuple2  tuple2 = tuple1;  // 输出 tuple2 的值,应该与 tuple1 相同  std::cout << std::get<0>(tuple2) << " " << std::get<1>(tuple2) << " " << std::get<2>(tuple2) << std::endl;  // 输出:1 2 three  return 0;  
}

上面的示例首先创建了一个名为 tuple1 的 tuple 并进行了初始化。然后,创建了一个名为 tuple2 的未初始化的 tuple,它的类型与 tuple1 相同。接下来,使用赋值运算符 = 将 tuple1 的值赋给了 tuple2。最后,通过 std::get 函数输出了 tuple2 的值,可以看到它的值与 tuple1 相同。

(2)拷贝操作

std::tuple 的拷贝操作通常是在创建新的 tuple 对象时隐式进行的,即通过使用已存在的 tuple 对象来初始化新的 tuple 对象。在拷贝过程中,源 tuple 中的每个元素都会被复制到新创建的 tuple 中。

下面是一个示例,展示了如何进行 std::tuple 的拷贝操作:

#include <tuple>  
#include <iostream>  
#include <string>   int main() 
{  // 创建并初始化第一个 tuple  std::tuple<int, double, std::string> tuple1(1, 2.0, "three");  // 使用 tuple1 来初始化第二个 tuple,这是一个拷贝操作  std::tuple<int, double, std::string> tuple3(tuple1);  // 输出 tuple3 的值,应该与 tuple1 相同  std::cout << std::get<0>(tuple3) << " " << std::get<1>(tuple3) << " " << std::get<2>(tuple3) << std::endl;  // 输出:1 2 three  return 0;  
}

上面的示例通过将 tuple1 作为参数传递给 tuple3 的构造函数来创建 tuple3。这是一个拷贝操作,因为 tuple3 是通过复制 tuple1 的值来初始化的。最后,输出了 tuple3 的值,可以看到它的值与 tuple1 相同。

需要注意的是,std::tuple 的赋值和拷贝操作都是浅拷贝(shallow copy),即对于包含指针或引用等复杂类型的 tuple,只会复制指针或引用的值,而不会复制指针或引用所指向的实际数据。如果需要进行深拷贝(deep copy),即复制指针或引用所指向的实际数据,需要自己实现相应的拷贝逻辑。

3.2 std::tuple 的比较操作

std::tuple 默认不提供直接的比较操作,因为其中包含的元素类型可能不同,而且不同类型之间的比较可能没有明确定义。

但是,可以通过重载比较运算符或提供自定义的比较函数来定义 std::tuple 之间的比较逻辑。一种常见的方法是编写一个自定义的比较函数,该函数接受两个 std::tuple 作为参数,并返回一个布尔值来表示它们之间的关系(如相等、小于等)。在这个函数中,可以根据需要比较 tuple 中的每个元素。

例如,假设有一个包含两个元素的 tuple(一个 int 和一个 double),则可以这样定义比较函数:

#include <tuple>  
#include <iostream>  bool compareTuples(const std::tuple<int, double>& t1, const std::tuple<int, double>& t2) {  if (std::get<0>(t1) != std::get<0>(t2)) {  return std::get<0>(t1) < std::get<0>(t2); // 先比较第一个元素  } else {  return std::get<1>(t1) < std::get<1>(t2); // 如果第一个元素相等,则比较第二个元素  }  
}  int main() 
{  std::tuple<int, double> t1(1, 2.0);  std::tuple<int, double> t2(2, 1.0);  std::tuple<int, double> t3(1, 3.0);  std::cout << std::boolalpha; // 输出 bool 值为 true 或 false 而不是 1 或 0  std::cout << "t1 < t2: " << compareTuples(t1, t2) << std::endl; // 输出: t1 < t2: true  std::cout << "t1 < t3: " << compareTuples(t1, t3) << std::endl; // 输出: t1 < t3: true  std::cout << "t2 < t3: " << compareTuples(t2, t3) << std::endl; // 输出: t2 < t3: false  return 0;  
}

在上面的示例中,compareTuples 函数首先比较两个 tuple 的第一个元素(一个 int)。如果它们不相等,函数就返回比较结果。如果第一个元素相等,函数就继续比较第二个元素(一个 double)。这种方法允许按照所需要的顺序和逻辑来比较 tuple 中的元素。

3.3 std::tie 的使用

std::tie 是 C++ 标准库中的一个函数,它主要用于创建一个包含左值引用的 std::tuple 对象。这个函数在需要将多个变量绑定到一个元组,或者需要将一个元组解包为独立对象时特别有用。

(1)定义与用法

std::tie 的定义如下:

template<class... Types>   
tuple<Types&...> tie(Types&... args) noexcept;

这里,Types&… args 是一个模板参数包,它接受任意数量和类型的左值引用参数。std::tie 函数返回一个 std::tuple,其中包含传入参数的左值引用。

(2)使用示例

下面是一个使用 std::tie 的简单示例:

#include <iostream>  
#include <tuple>  int main() 
{  int x = 10;  int y = 20;  int z = 30;  // 使用 std::tie 将变量 x, y, z 绑定到元组中  std::tie(x, y, z) = std::make_tuple(z, x, y);  std::cout << "x: " << x << std::endl; // 输出: 30  std::cout << "y: " << y << std::endl; // 输出: 10  std::cout << "z: " << z << std::endl; // 输出: 20  return 0;  
}

这个例子首先创建了三个整数变量 x、y 和 z,并分别初始化为 10、20 和 30。然后,使用 std::tie 将这些变量绑定到一个元组中,并使用 std::make_tuple 创建了一个新的元组,其中元素的顺序为 z、x、y。通过赋值操作,实际上交换了 x、y 和 z 的值。

(3)在结构体中的使用

std::tie 也可以用于结构体的成员函数,以便返回结构体的多个成员。例如:

#include <iostream>  
#include <string>  
#include <tuple>  struct Test {  int id;  std::string name;  // ... 其他成员 ...  auto tie() const {  return std::tie(id, name /*, ... 其他成员 ... */);  }  
};  int main() 
{  Test t1{1, "Alice"};  Test t2{2, "Bob"};  if (t1.tie() == t2.tie()) {  std::cout << "t1 and t2 are equal" << std::endl;  } else {  std::cout << "t1 and t2 are not equal" << std::endl;  }  return 0;  
}

上面代码的输出为:

t1 and t2 are not equal

在这个例子中,Test 结构体有一个 tie 成员函数,它返回一个包含 id 和 name 成员的 std::tuple。然后,我们可以使用这个 tie 函数来比较两个 Test 对象的相应成员是否相等。

(4)注意事项

  • 使用 std::tie 时,必须确保绑定的变量是左值,即它们必须有明确的存储位置(不能是临时对象或右值)。
  • std::tie 创建的元组包含对原始变量的引用,因此对元组中的元素所做的任何修改都会反映到原始变量上。
  • 当不再需要 std::tie 创建的元组时,应确保不会意外地修改或销毁通过引用绑定的变量,这可能会导致悬挂引用或未定义行为。

3.4 std::ignore 在 std::tuple 中的使用

std::ignore 是 C++ 标准库中的一个特殊工具,主要用于在解包 std::tuple 或处理结构化绑定时忽略某些不需要的元素。这在处理包含多个返回值或参数的函数或数据结构时特别有用,特别是当你只对其中一部分返回值或参数感兴趣时。

(1)使用场景

当使用 std::get 从 tuple 中提取特定元素时,或者在使用结构化绑定时,可能不想处理 tuple 中的所有元素。在这些情况下,可以使用 std::ignore 来指示编译器忽略不关心的元素。

(2)示例

假设有一个返回三个值的函数,但只关心前两个值:

#include <tuple>  
#include <iostream>  std::tuple<int, double, std::string> getValues() {  return std::make_tuple(10, 20.5, "Hello");  
}  int main() 
{  auto values = getValues();  // 使用 std::ignore 忽略第三个元素  int a;  double b;  std::ignore = std::get<2>(values); // 忽略第三个元素  std::tie(a, b, std::ignore) = values; // 只提取前两个元素  std::cout << "a: " << a << ", b: " << b << std::endl;  // 输出: a: 10, b: 20.5  return 0;  
}

在上面的示例中,getValues 函数返回一个包含三个元素的 tuple。在 main 函数中,只关心前两个元素(一个 int 和一个 double)。所以使用 std::ignore 来忽略第三个元素(一个 std::string),并通过 std::tie 提取前两个元素的值。

(3)注意事项

  • std::ignore 本身是一个对象,但当将其用作绑定目标时,编译器会特殊处理它,使其忽略对应的值。
  • 当只关心 tuple 中的部分元素时,使用 std::ignore 可以使代码更清晰,避免不必要的变量声明和未使用的警告。
  • std::ignore 主要用于解包操作,不适用于其他场景,比如直接赋值或比较操作。在这些情况下,需要显式地处理所有元素。

4 使用 std::tuple 实现多返回值函数

下面是一个示例,展示了如何定义一个返回std::tuple的函数,并如何使用std::get来提取返回元组中的各个值:

#include <iostream>  
#include <tuple>  
#include <string>  // 定义一个返回std::tuple的函数  
std::tuple<int, double, std::string> get_multiple_values() {  int a = 10;  double b = 20.5;  std::string s = "Hello, tuple!";  return std::make_tuple(a, b, s);  
}  int main() 
{  // 调用函数并接收返回的元组  std::tuple<int, double, std::string> result = get_multiple_values();  // 使用std::get来访问元组中的元素  int int_value = std::get<0>(result);  double double_value = std::get<1>(result);  std::string string_value = std::get<2>(result);  // 打印解包后的值  std::cout << "Int: " << int_value << std::endl;  std::cout << "Double: " << double_value << std::endl;  std::cout << "String: " << string_value << std::endl;  return 0;  
}

上面代码的输出为:

Int: 10
Double: 20.5
String: Hello, tuple!

在这个例子中,get_multiple_values 函数返回一个包含 int、double 和 std::string 类型的 std::tuple。在 main 函数中,调用这个函数并将返回的元组存储在 result 变量中。然后,使用 std::get 函数和相应的索引来访问元组中的每个元素,并将它们分别存储在 int_value、double_value 和 string_value 变量中。最后,打印这些变量的值。

相关文章:

突破编程_C++_C++11新特性(tuple)

1 std::tuple 简介 1.1 std::tuple 概述 std::tuple 是一个固定大小的不同类型值的集合&#xff0c;可以看作 std::pair 的泛化&#xff0c;即 std::pair 是 std::tuple 的一个特例&#xff0c;其长度受限为 2。与 C# 中的 tuple 类似&#xff0c;但 std::tuple 的功能更为强…...

xss.pwnfunction(DOM型XSS)靶场

环境进入该网站 Challenges (pwnfunction.com) 第一关&#xff1a;Ma Spaghet! 源码&#xff1a; <!-- Challenge --> <h2 id"spaghet"></h2> <script>spaghet.innerHTML (new URL(location).searchParams.get(somebody) || "Somebo…...

安装 docker 和 jenkins

安装 docker #安装 软件包 docker yum install -y yum-utils device-mapper-persistent-data lvm2#设置 yum 源 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-c…...

jni入门学习 CMakeLists脚本

在 Android Studio 中使用 CMake 可以编译 C/C 代码&#xff0c;这为开发者提供了在 Android 应用中嵌入本地代码的能力。下面是关于在 Android Studio 中使用 CMake 编译的详细说明&#xff1a; 1. 创建 CMakeLists.txt 文件&#xff1a; 首先&#xff0c;你需要在项目的根目…...

如何在没有向量数据库的情况下使用知识图谱实现RAG

引言 传统上&#xff0c;为大型语言模型&#xff08;LLMs&#xff09;提供长期记忆通常涉及到使用检索增强生成&#xff08;RAG&#xff09;解决方案&#xff0c;其中向量数据库作为长期记忆的存储机制。然而&#xff0c;我们是否能在没有向量数据库的情况下达到相同效果呢&am…...

6.如何判断数据库搜索是否走索引?

判断是否使用索引搜索 索引在数据库中是一个不可或缺的存在&#xff0c;想让你的查询结果快准狠&#xff0c;还是需要索引的来帮忙&#xff0c;那么在mongo中如何判断搜索是不是走索引呢&#xff1f;通常使用执行计划&#xff08;解释计划、Explain Plan&#xff09;来查看查询…...

Java并发编程的性能优化方案中,哪些方法比较常用

在Java并发编程的性能优化方案中&#xff0c;以下是一些常用的方法&#xff1a; 线程池的使用&#xff1a; 线程池可以复用线程&#xff0c;避免频繁地创建和销毁线程&#xff0c;从而提高系统性能。常用的线程池有FixedThreadPool、CachedThreadPool等。根据任务特性选择合适…...

AcWing 2867. 回文日期(每日一题)

原题链接&#xff1a;2867. 回文日期 - AcWing题库 2020 年春节期间&#xff0c;有一个特殊的日期引起了大家的注意&#xff1a;2020 年 2 月 2 日。 因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202&#xff0c;恰好是一个回文数。 我们称这样的日期是…...

学习笔记-华为IPD转型2020:3,IPD的实施

3. IPD的实施 1999 年开始的 IPD 转型是计划中的多个转型项目中的第一个&#xff08;Liu&#xff0c;2015&#xff09;。华为为此次转型成立了一个专门的团队&#xff0c;从大约20人开始&#xff0c;他们是华为第一产业的高层领导。董事会主席孙雅芳是这个团队的负责人。该团…...

2024腾龙杯web签到题-初识jwt(签到:这是一个登录页面)

什么是 jwt? 它是 JSON Web Token 的缩写&#xff0c;是一个开放标准&#xff0c;定义了一种紧凑的、自包含的方式&#xff0c;用于作为JSON对象在各方之间安全地传输信息&#xff0c;该信息可以被验证和信任&#xff0c;因为它是数字签名的。它就是一种认证机制&#xff0c;…...

Monaco Editor系列(一)启动项目与入门示例解析

前言&#xff1a;作为一名程序员&#xff0c;我们工作中的每一天都在与代码编辑器打交道&#xff0c;相信各位前端程序员对 VS Code 一定都不陌生&#xff0c;VS Code 可以为我们提供代码高亮、代码对比等等功能&#xff0c;让我们在开发的时候&#xff0c;不需要对着暗淡无光的…...

DNA存储技术原理是什么?

随着大数据和人工智能的发展&#xff0c;全球每天产生的数据量剧增&#xff0c;对存储设备的需求也随之增长&#xff0c;数据存储问题日益凸显。传统的硬盘驱动器&#xff08;HDD&#xff09;、磁带等冷存和深度归档存储占据数据中心存储的60-70%&#xff0c;由于它们的访问频率…...

多维时序 | Matlab实现VMD-CNN-GRU变分模态分解结合卷积神经网络门控循环单元多变量时间序列预测

多维时序 | Matlab实现VMD-CNN-GRU变分模态分解结合卷积神经网络门控循环单元多变量时间序列预测 目录 多维时序 | Matlab实现VMD-CNN-GRU变分模态分解结合卷积神经网络门控循环单元多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现VMD-CN…...

基于springboot+vue的毕业论文管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…...

JavaWeb后端——分层解耦 IOC DI

分层/三层架构概述 三层架构&#xff1a;Controller、Service、Dao 解耦/IOC&DI概述 分层解耦 容器称为&#xff1a;IOC容器/Spring容器 IOC 容器中创建&#xff0c;管理的对象&#xff0c;称为&#xff1a;bean 对象 IOC&DI入门 实现 IOC&DI 需要的注解&#…...

短视频矩阵系统技术交付

短视频矩阵系统技术交付&#xff0c;短视频矩阵剪辑矩阵分发系统现在在来开发这个市场单个项目来说&#xff0c;目前基本上已经沉淀3年了&#xff0c;那么我们来就技术短视频矩阵剪辑系统开发来聊聊 短视频矩阵系统经过315大会以后&#xff0c;很多违规的技术开发肯定有筛选到了…...

Halcon 凹坑检测案例

* 使用元组的方法 ImageFile:[] ImageFile[0]:D:/Halcon/产品上的凹坑检测/1.bmp ImageFile[1]:D:/Halcon/产品上的凹坑检测/2.bmp for Index : 0 to |ImageFile|-1 by 1read_image (Image, ImageFile[Index])* 二值化threshold (Image, Region, 100, 255)* 连通性connection (…...

MD5算法:密码学中的传奇

title: MD5算法&#xff1a;密码学中的传奇 date: 2024/3/15 20:08:07 updated: 2024/3/15 20:08:07 tags: MD5起源算法原理安全分析优缺点比较技术改进示例代码应用趋势 MD5算法起源&#xff1a; MD5&#xff08;Message Digest Algorithm 5&#xff09;算法是由MIT的计算机…...

microk8s使用本地私服registry的镜像http协议

开发环境为了能部署服务到microk8s&#xff0c;我们开启了一个本地私库&#xff0c;地址为&#xff1a;http://localhost:5000&#xff0c;那么如何在microk8s中能拉取本地私库中的镜像呢? 直接部署的话&#xff0c;microk8s会用https协议去拉取镜像&#xff0c;所以必须要配置…...

C++初阶 | [九] list 及 其模拟实现

摘要&#xff1a;介绍 list 容器&#xff0c;list 模拟实现&#xff0c;list与vector的对比 list&#xff08;带头双向循环列表&#xff09; 导入&#xff1a;list 的成员函数基本上与 vector 类似&#xff0c;具体内容可以查看相关文档(cplusplus.com/reference/list/list/)&…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁

赛门铁克威胁猎手团队最新报告披露&#xff0c;数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据&#xff0c;严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能&#xff0c;但SEMR…...

ThreadLocal 源码

ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物&#xff0c;因为每个访问一个线程局部变量的线程&#xff08;通过其 get 或 set 方法&#xff09;都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段&#xff0c;这些类希望将…...