C++基础11:模板与命名空间

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C++从入门到深入的专栏,参考书籍:《深入浅出 C {\rm C} C++》(马晓锐)和《从 C {\rm C} C C {\rm C} C++精通面向对象编程》(曾凡锋等)。



10.模板与命名空间
10.1 模板简述
  • 模板使函数和类的处理对象参数化,使代码具有通用性;

  • C {\rm C} C++程序的组成单位是函数和类,因此,模板分为函数模板 ( f u n c t i o n   t e m p l a t e ) ({\rm function\ template}) (function template)和类模板 ( c l a s s   t e m p l a t e ) ({\rm class\ template}) (class template);定义模板后,可以处理不同的数据类型,不必显式定义针对不同数据类型的函数或类;

  • 模板、函数模板、类模板与对象间的关系如下:

    15

  • 模板可以最大限度地实现代码重用,使代码精简;

10.2 函数模板
  • 函数模板是一类可以被实例化的特殊函数,通过模板可以操作通用类型的数据,函数模板处理的数据类型是通过参数来体现,在函数模板实例化的过程中,才将这些参数具体化为一种特定的数据类型,因此,在定义函数时不用为每种数据类型都编写重复的相似代码;模板中表示数据类型的参数称为模板参数,这是一种特殊的参数,能传递一种数据类型;

  • 声明函数模板参数类型的语法格式:

    // 声明格式1:
    template <class 类型标识符> 返回类型 函数名(函数形参表);
    
    // 声明格式2:
    template <typename 类型标识符> 返回类型 函数名(函数形参表);
    
    • t e m p l a t e {\rm template} template是声明模板的关键字,表示声明一个模板;
    • t e m p l a t e {\rm template} template关键字后是用尖括号’<>'括起来的类型参数表,类型参数表中包含一个或多个由逗号分隔的类型参数项,每一项由关键字 c l a s s {\rm class} class和用户命名的标识符组成,此标识符为类型参数,不是一种数据类型,可以同一般数据类型一样使用在函数的任何地方;
  • 调用函数模板的语法格式:

    函数名<具体类型>(参数表);
    
  • 在调用函数模板时,<具体类型>可以省略,由系统自动判定;当<具体类型>不省略时,为显式实例化,当<具体类型>省略时,为隐式实例化;

  • 函数模板接收参数类型问题:

    // 定义一个返回两个对象中较大对象的函数模板;
    // 下面的函数模板只能接收相同参数,不能接收两个不同的参数;
    // 因为只包含了一种类型的模板参数typename TheType;
    template <typename TheType>
    TheType GetMax(TheType a,TheType b)
    {
        return (a>b?a:b);
    }
    
    // 下面的函数模板可以接收两个不同类型的参数;
    template <typename TheType1,typename TheType2>
    TheType1 GetMax(TheType1 a,TheType2 b)
    {
        return (a>b?a:b);
    }
    
  • 函数模板实例:定义一个操作数组的函数模板,完成遍历数组输出元素的功能 ( e x a m p l e 10 _ 1. c p p ) ({\rm example10\_1.cpp}) (example10_1.cpp)

    /**
     * 作者:罗思维
     * 时间:2024/03/24
     * 描述:定义一个操作数组的函数模板,完成遍历数组输出元素的功能
     */
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    // 定义函数模板;
    template <class T>
    void printArray(const T *array, const int count) {
    	for (int i = 0; i < count; i++) {
    		cout << array[i] << " ";
    	}
    	cout << endl;
    }
    
    int main() {
    	int nArray[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    	char cArray[] = {'W', 'E', 'L', 'C', 'O', 'M', 'E'};
    
    	// 调用函数模板输出整型数组和字符数组中元素;
    	printArray(nArray, sizeof(nArray) / sizeof(int));
    	printArray(cArray, sizeof(cArray) / sizeof(char));
    	return 0;
    }
    
  • 模板函数可以像普通函数一样被重载,实例如下 ( e x a m p l e 10 _ 2. c p p ) ({\rm example10\_2.cpp}) (example10_2.cpp)

    /**
     * 作者:罗思维
     * 时间:2024/03/24
     * 描述:模板函数重载。
     */
    #include <iostream>
    #include <string.h>
    
    using namespace std;
    
    // 定义函数模板;
    template <typename TheType>
    TheType GetMax(TheType a, TheType b) {
    	return (a > b ? a : b);
    }
    
    // 重载函数模板,使函数模板支持字符串的处理;
    char* GetMax(char* a, char* b) {
    	return (strcmp(a, b) > 0 ? a : b);
    }
    
    int main() {
    	int nNumber1 = 10, nNumber2 = 20;
    	float fNumber1 = 13.14, fNumber2 = 5.20;
    
    	char a = 'L', b = 'C';
    	char *p1 = (char*)"C++";
    	char *p2 = (char*)"Python";
    
    	cout << "GetMax(10,20):" << GetMax(nNumber1, nNumber2) << endl;
    	cout << "GetMax(13.14,5.20):" << GetMax(fNumber1, fNumber2) << endl;
    
    	cout << "GetMax('L','C'):" << GetMax(a, b) << endl;
    	cout << "GetMax('C++','Python'):" << GetMax(p1, p2) << endl;
    
    	return 0;
    }
    
10.3 类模板
  • 类模板的作用:将类所处理的对象类型参数化,它使得类中的某些数据成员的参数和返回值能取任意数据类型;

  • 类模板定义的语法格式:

    template <类型参数表>
    class 类名
    {
        // 类体
    };
    
    • t e m p l a t e {\rm template} template:声明模板的关键字,表示声明一个模板类;
    • <类型参数表>中包含一个或多个类型参数项,每一项由关键字 c l a s s {\rm class} class和一个用户自定义的标识符组成,标识符为类型参数;
    • 使用类模板时,先将其实例化,即用实际的数据类型代替类型参数;
    • 当类模板中的成员函数在类定义体外定义时,必须被定义为一个函数模板的形式;
  • 类模板实战项目 ( c l a s s T e m p l a t e ) ({\rm classTemplate}) (classTemplate)

    • 项目需求:定义一个简单通用数组类模板,实现对一般数据类型数组的操作;

    • C A r r a y {\rm CArray} CArray类定义头文件 ( C A r r a y . h ) ({\rm CArray.h}) (CArray.h)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:CArray类定义头文件。 
       */
      #pragma once
      #include <iostream>
      #include <iomanip>
      #include <string.h>
      
      using namespace std;
      
      const int MIN_SIZE = 30;
      
      // 定义模板类 
      template <class T>
      class CArray {								// 数组类; 
      	protected:
      		T* m_pArray;						// 数组指针; 
      		int m_nSize;						// 数组元素个数; 
      	public:
      		CArray(int nSize, T Initial);		// 构造函数,初始化数组; 
      		~CArray() {							// 析构函数,释放内存; 
      			delete[] m_pArray;
      		};
      		T& operator[] (int nIndex) {		// 重载数组下标运算符; 
      			return m_pArray[nIndex];
      		};
      		void Show(const int nNumElems);		// 输出前nNumElems个元素; 
      		void Sort(int nNumElems);			// 将前nNumElems个元素进行排序; 
      };
      
      template <class T>
      CArray<T>::CArray(int nSize, T InitVal) {
      	m_nSize = (nSize > 1) ? nSize : 1;		// 保证nSize不小于1; 
      	m_pArray = new T[m_nSize];
      	for (int i = 0; i < m_nSize; i++) {
      		m_pArray[i] = InitVal;				// 将元素全部初始化为InitVal; 
      	}
      }
      
      template <class T>
      void CArray<T>::Show(const int nNumElems) {
      	for (int i = 0; i < nNumElems; i++) {
      		cout << m_pArray[i] << ' ';
      	}
      }
      
      template <class T>
      void CArray<T>::Sort(int nNumElems) {		// 对元素进行排序; 
      	int nOffset = nNumElems;
      	bool bSorted;
      	if (nNumElems < 2) {
      		return;
      	}
      	do {
      		nOffset = (nOffset * 8) / 11;
      		nOffset = (nOffset < 1) ? 1 : nOffset;
      		bSorted = true;
      		for (int i = 0, j = nOffset; i < (nNumElems - nOffset); i++, j++) {
      			if (m_pArray[i] > m_pArray[j]) {
      				T nSwap = m_pArray[i];
      				m_pArray[i] = m_pArray[j];
      				m_pArray[j] = nSwap;
      				bSorted = false;
      			}
      		}
      	} while (!bSorted || nOffset != 1);
      }
      
    • C M y S t r i n g {\rm CMyString} CMyString类定义头文件 ( C M y S t r i n g . h ) ({\rm CMyString.h}) (CMyString.h)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:CMyString类定义头文件。 
       */
      #pragma once
      #include "CArray.h"
      
      // 定义字符串类; 
      class CMyString {
      	protected:
      		char* m_pszString;					// 字符串指针; 
      		int m_nSize;						// 字符串中的字符个数; 
      	public:
      		CMyString(int nSize = MIN_SIZE) {
      			m_pszString = new char[m_nSize = nSize];
      		};
      		CMyString(const CMyString& CString);
      		CMyString(const char* pszString);
      		CMyString(const char cChar);
      		~CMyString() {
      			delete[] m_pszString;
      		};
      		int getLen() {
      			return strlen(m_pszString);
      		};
      		int getMaxLen() {
      			return m_nSize;
      		};
      
      		// 重载运算符= 
      		CMyString& operator=(const CMyString& aString);
      		CMyString& operator=(const char* pszString);
      		CMyString& operator=(const char cChar);
      
      		// 重载运算符> 
      		friend operator > (CMyString& aString1, CMyString& aString2) {
      			return (strcmp(aString1.m_pszString, aString2.m_pszString) > 0) ? 1 : 0;
      		}
      		friend ostream& operator << (ostream& os, CMyString& aString);
      };
      
    • C M y S t r i n g {\rm CMyString} CMyString类实现文件 ( C M y S t r i n g . c p p ) ({\rm CMyString.cpp}) (CMyString.cpp)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:CArray类实现文件。 
       */
      #include "CMyString.h"
      
      CMyString::CMyString(const CMyString &aString) {
      	m_pszString = new char[m_nSize = aString.m_nSize];
      	strcpy(m_pszString, aString.m_pszString);
      }
      
      CMyString::CMyString(const char *pszString) {
      	m_pszString = new char[m_nSize = strlen(pszString) + 1];
      	strcpy(m_pszString, pszString);
      }
      
      CMyString::CMyString(const char cChar) {
      	m_pszString = new char[m_nSize = MIN_SIZE];
      	m_pszString[0] = cChar;
      	m_pszString[1] = '\0';
      }
      
      CMyString &CMyString::operator=(const CMyString &aString) {
      	// 检查是否有足够的空间进行字符串的复制; 
      	if (strlen(aString.m_pszString) < unsigned(m_nSize)) {
      		strcpy(m_pszString, aString.m_pszString);
      	} else {
      		strncpy(m_pszString, aString.m_pszString, m_nSize - 1);
      	}
      
      	return *this;
      }
      
      CMyString &CMyString::operator=(const char *pszString) {
      	if (strlen(pszString) < unsigned(m_nSize)) {
      		strcpy(m_pszString, pszString);
      	} else {
      		strncpy(m_pszString, pszString, m_nSize - 1);
      	}
      
      	return *this;
      }
      
      CMyString &CMyString::operator=(const char cChar) {
      	if (m_nSize > 1) {
      		m_pszString[0] = cChar;
      		m_pszString[1] = '\0';
      	}
      
      	return *this;
      }
      
      // 输出对象重载; 
      ostream &operator << (ostream &os, CMyString &aString) {
      	os << aString.m_pszString;
      	return os;
      }
      
    • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

      /**
       * 作者:罗思维
       * 时间:2024/03/25
       * 描述:程序主文件。 
       */
      #include <iostream>
      #include "CMyString.h"
      
      using namespace std;
      
      int main() {
      	const int MAX_ELEMS = 10;
      	int nArr[MAX_ELEMS] = {10, 20, 40, 50, 60, 90, 80, 70, 30, 100};
      	char cArr[MAX_ELEMS] = {'C', 'W', 'r', 'Y', 'k', 'J', 'X', 'Z', 'y', 's'};
      
      	CArray<int> IntegerArray(MAX_ELEMS, 0);			// 用int类型实例化通用数组类模板;
      	CArray<char> CharArray(MAX_ELEMS, ' ');			// 用char类型实例化通用数组类模板;
      	CArray<CMyString> StringArray(MAX_ELEMS, " ");	// 用自定义类型CMyString实例化通用数组类模板;
      
      	for (int i = 0; i < MAX_ELEMS; i++) {
      		IntegerArray[i] = nArr[i];
      	}
      
      	for (int i = 0; i < MAX_ELEMS; i++) {
      		CharArray[i] = cArr[i];
      	}
      
      	StringArray[0] = "GuangDong";
      	StringArray[1] = "BeiJing";
      	StringArray[2] = "HuBei";
      	StringArray[3] = "GuiZhou";
      	StringArray[4] = "GuangXi";
      	StringArray[5] = "HuNan";
      	StringArray[6] = "ShanDong";
      	StringArray[7] = "ShanXi";
      	StringArray[8] = "JiangSu";
      	StringArray[9] = "ZheJiang";
      
      	// 输出IntegerArray排序前后的内容;
      	cout << "Unsorted array is:" << endl;
      	IntegerArray.Show(MAX_ELEMS);
      	IntegerArray.Sort(MAX_ELEMS);
      	cout << "\nSorted array is:" << endl;
      	IntegerArray.Show(MAX_ELEMS);
      	cout << endl;
      
      	// 输出CharArray排序前后的内容;
      	cout << "Unsorted array is:" << endl;
      	CharArray.Show(MAX_ELEMS);
      	CharArray.Sort(MAX_ELEMS);
      	cout << "\nSorted array is:" << endl;
      	CharArray.Show(MAX_ELEMS);
      	cout << endl;
      
      	// 输出StringArray排序前后的内容;
      	cout << "\nUnsorted array is:" << endl;
      	StringArray.Show(MAX_ELEMS);
      	StringArray.Sort(MAX_ELEMS);
      	cout << "\nSorted array is:" << endl;
      	StringArray.Show(MAX_ELEMS);;
      
      	return 0;
      }
      
10.4 命名空间
  • 命名空间是 A N S I   C {\rm ANSI\ C} ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突;

  • C {\rm C} C++中的作用域有文件作用域、函数作用域、复合语句作用域和类作用域等,在不同的作用域中,定义具有相同名称的变量是合法的;

  • 在文件中可以定义全局变量,作用域是整个程序,在同一个作用域中不应该出现两个或多个同名的实体;

  • 在大型软件开发中,一般程序分模块完成,在各模块中可能会产生同名的实体,从而产生命名冲突;

  • 如果引用标准库、第三方库、自定义库中包含与程序中定义的全局实体同名的实体,或不同库之间有同名的实体,则编译时出现命名冲突,称为全局命名空间污染 ( g l o b a l   n a m e s p a c e   p o l l u t i o n ) ({\rm global\ namespace\ pollution}) (global namespace pollution)

  • 命名空间是由开发者命名的一个作用域区域,这些区域称为空间域,开发者可以根据需要指定一些有名称的空间域,把自定义的实体放在这个空间域中,保证使其与外界分离,这样可以使空间域内部实体不会与外界产生冲突;

  • 命名空间定义的语法格式:

    namespace <命名空间名>
    {
        ...;	// 命名空间实体;
    }
    
    • n a m e s p a c e {\rm namespace} namespace:定义命名空间的关键字;
    • <命名空间名>:用户指定的命名空间的名称;
    • 大括号内是声明块,在其中声明的实体称为命名空间成员 ( n a m e s p a c e   m e m b e r ) ({\rm namespace\ member}) (namespace member),命名空间成员可以包含变量、常量、结构体、类、模板、命名空间等;
  • 命名空间举例:

    namespace myns
    {
        int a;
        char c;
    }
    
    • 在程序中使用变量 a 、 c {\rm a、c} ac,需要加上命名空间名和作用域限定符" : : :: ::",如: m y n s : : a 、 m y n s : : c {\rm myns::a、myns::c} myns::amyns::c,此用法称为命名空间限定 ( q u a l i f i e d ) ({\rm qualified}) (qualified) m y n s : : a {\rm myns::a} myns::a称为被限定名 ( q u a l i f i e d   n a m e ) ({\rm qualified\ name}) (qualified name)
  • 程序开发过程中,可以根据实际情况定义多个命名空间,把不同的库中的实体放到不同的命名空间中,即用不同的命名空间把不同的实体隐藏起来;

  • 对命名空间成员引用的语法格式:

    命名空间::命名空间成员名
    
  • 命名空间的几种使用方法:

    • 定义命名空间后,可以为其起一个别名:

      // 声明命名空间,名为:NameSpaceGraduateStudent;
      namespace NameSpaceGraduateStudent
      {
          ...;
      }
      
      // 给命名空间起别名;
      namespace NSGS=NameSpaceGraduateStudent;
      
    • 使用 u s i n g {\rm using} using引入命名空间中的成员, u s i n g {\rm using} using的作用是引入命名空间或命名空间中的成员,其后面必须是由命名空间限定的名称;

      // 用using引入命名空间中的成员;
      // 引入后可以直接引用CStudent即可;
      using Stu::CStudent;
      
      // 等价关系;
      Stu::CStudent student ("Willard")	等价于		CStudent student ("Willard")
      
    • 使用 u s i n g   n a m e s p a c e {\rm using\ namespace} using namespace引入命名空间,可以一次性引入命名空间的全部成员,语法格式:

      using namespace 命名空间名;
      
    • 无名的命名空间,在其他文件中无法使用,只能在本文件的作用域有效,语法格式:

      namespace
      {
          // 定义命名空间名;
          void func()
          {
              ...;
          }
      }
      
  • 标准命名空间 s t d {\rm std} std,在程序中没有引入标准命名空间时,要使用其中的成员,则使用 s t d {\rm std} std来进行限定;

  • C {\rm C} C++头文件的作用:为用户提供调用其实现的外部接口;

10.5 实战

项目需求

约瑟夫 ( J o s e p h u s ) ({\rm Josephus}) (Josephus)问题:假设有 n n n个小孩做成一个环,从第一个小孩开始数数,如果数到第 m m m个小孩,则该小孩离开,问最后留下的小孩是第几个小孩?

问题分析

如果总共有 6 6 6个小孩,围成一圈,从第一个小孩开始,每次数 2 2 2个小孩,则游戏情况过程:

小孩序号: 1 、 2 、 3 、 4 、 5 、 6 1、2、3、4、5、6 123456

离开小孩序号: 2 、 4 、 6 、 3 、 1 2、4、6、3、1 24631

则获胜小孩序号为: 5 5 5

代码实现 ( J o s e p h u s ) ({\rm Josephus}) (Josephus)

  • J o s e p h u s R i n g . h {\rm JosephusRing.h} JosephusRing.h代码:

    /**
     * 作者:罗思维
     * 时间:2024/03/26
     * 描述:JosephusRing类定义头文件; 
     */
    #pragma once
    #include <iostream>
    #include <iterator>			// iterator:迭代器 
    #include <list>				// list是一个容器,其结构为双向链表;
    
    using namespace std;
    
    template <class Type>
    class JosephusRing {
    		list <Type> lst;
    
    	public:
    		class iterator;
    		friend class iterator;
    		class iterator: public std::iterator<std::bidirectional_iterator_tag, Type, ptrdiff_t> {
    				typename list<Type>::iterator it;
    				list<Type>* r;
    			public:
    				iterator(list<Type>& lst, const typename list<Type>::iterator& i): it(i), r(&lst) {};
    				bool operator==(const iterator& x) const {
    					return it == x.it;
    				};
    				bool operator!=(const iterator& x) const {
    					return !(*this == x);
    				};
    				typename list<Type>::reference operator*() const {
    					return *it;
    				};
    				iterator& operator++() {
    					++it;
    					if (it == r->end()) {
    						it = r->begin();
    					}
    					return *this;
    				};
    				iterator operator++(int) {
    					iterator tmp = *this;
    					++* this;
    					return tmp;
    				};
    				iterator& operator--() {
    					if (it == r->begin()) {
    						it = r->end();
    					}
    					--it;
    					return *this;
    				};
    				iterator operator--(int) {
    					iterator tmp = *this;
    					--*this;
    					return tmp;
    				};
    				iterator insert(const Type& x) {
    					return iterator(*r, r->insert(it, x));
    				};
    				iterator erase() {
    					return iterator(*r, r->erase(it));
    				};
    		};
    
    		void push_back(const Type& x) {
    			lst.push_back(x);
    		};
    
    		iterator begin() {
    			return iterator(lst, lst.begin());
    		};
    
    		int size() {
    			return lst.size();
    		}
    };
    
  • 程序主文件 ( m a i n . c p p ) ({\rm main.cpp}) (main.cpp)

    /**
     * 作者:罗思维
     * 时间:2024/03/26
     * 描述:程序主文件。 
     */
    #include "JosephusRing.h"
    
    int main() {
    	int n, m;
    	cout << "请输入小孩总数:";
    	cin >> n;
    
    	cout << "每次数的孩子数:";
    	cin >> m;
    
    	JosephusRing<int> Josephus;
    	for (int i = 1; i <= n; i++) {
    		Josephus.push_back(i);
    	}
    
    	JosephusRing<int>::iterator tmp = Josephus.begin();
    	JosephusRing<int>::iterator it = tmp;
    
    	for (int index = 0; index < n - 1; index++) {
    		it = tmp;
    		for (int j = 0; j < m - 1; j++) {
    			it++;
    			tmp++;
    		}
    		tmp++;
    		cout << "离开的孩子:" << *it << endl;
    		it.erase();
    	}
    	it = Josephus.begin();
    
    	cout << "最后剩下的孩子:" << *it << endl;
    
    	return 0;
    }
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RecyclerView notifyItemChanged 之后的源码分析

注意&#xff1a;本文是基于 androidx.RecyclerView 1.3.2 版本的源码分析。默认使用 DefaultItemAnimator&#xff0c;如果使用了其他的 ItemAnimator&#xff0c;可能会有不同的表现。 效果图&#xff1a; 示例代码如下&#xff1a; binding.btnNotifyItemChanged.setOnCli…

openstack 不能调度到某主机上分析

dashboard显示有足够资源创建虚拟机 创建一个1c2g20g配置的虚拟机&#xff0c;在过滤时把10-197-0-2这个主机过滤掉了&#xff0c;日志如下&#xff1a; 2024-03-25 17:52:14.087 26 DEBUG nova.scheduler.filters.disk_filter [req-8f2f32fb-1efe-4e5d-81fc-618210c7c76d 773…

TorchAcc:基于 TorchXLA 的分布式训练框架

演讲人&#xff1a;林伟&#xff0c;阿里云研究员&#xff0c;阿里云人工智能平台 PAI 技术负责人 本文旨在探讨阿里云 TorchAcc&#xff0c;这是一个基于 PyTorch/XLA 的大模型分布式训练框架。 过去十年 AI 领域的显著进步&#xff0c;关键在于训练技术的革新和模型规模的快…

【XXL-JOB】执行器架构设计和源码解析

简介 XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c;开箱即用。 XXL-JOB分为B/S架构&#xff0c;调用中心是XXL-JOB服务端&#xff0c;执行器是客户端。 调度中心核…

【1】网络协议基础概念

【1】网络协议基础知识 1、互联网2、为什么要学习网络协议3、学习中需要搭建的环境4、客户端-服务器5、Java 的跨平台原理6、C/C的跨平台原理7、一个简单的SpringBoot项目(1) pom.xml(2) application.yml(3) NetworkStudyApp.java(4) SwaggerConfig.java(5) HelloWorldControll…

CXL系统架构

CXL系统架构 CXL支持三种设备类型&#xff0c;如下图。Type 1支持CXL.cache和CXL.io&#xff1b;Type 2支持CXL.cache&#xff0c;CXL.mem和CXL.io&#xff1b;Type 3支持CXL.mem和CXL.io。无论哪种类型&#xff0c;CXL.io都是不可缺少的&#xff0c;因为设备的发现&#xff0…

Deconstructing Denoising Diffusion Models for Self-Supervised Learning解读(超详细)

论文题目&#xff1a;Deconstructing Denoising Diffusion Models for Self-Supervised Learning 原文链接&#xff1a;https://arxiv.org/html/2401.14404v1 本文是对何凯明老师的新作进行的详细解读&#xff0c;其中穿插了一些思考&#xff0c;将从以下四个方面对这篇工作进…

3723. 字符串查询:做题笔记

目录 思路 代码 注意点 3723. 字符串查询 思路 这道题感觉和常见的前缀和问题不太一样&#xff0c;前缀和的另一种应用&#xff1a;可以统计次数。 这道题我们想判断一个单词的其中一段子序列A是否可以通过重新排列得到另一段子序列B。 我看到这道题的时候想着可能要判…

Gitlab 实现仓库完全迁移,包括所有提交记录、分支、标签

1 方案一&#xff1a;命令 cd <项目目录> git fetch --all git fetch --tags git remote rename origin old-origin #可以不保留 git remote add origin http://***(项目的新仓库地址) #git remote set-url origin <项目的新仓库地址> git push origin --all git…

Qt 多线程QThread的四种形式

重点&#xff1a; 1.互斥量&#xff1a;QMutex配套使用&#xff0c;lock(),unlock(),如果一个线程准备读取另一个线程数据时候采用tryLock()去锁定互斥量&#xff0c;保证数据完整性。 QMutexLocker简化版的QMutex,在范围区域内使用。 QMutex mutex QMutexLocker locker(&…

达梦数据库新手上路排坑

数据库安装 这个没啥说的&#xff0c;按照官网教程操作&#xff0c;我使用的是docker进行安装 下载文件docker文件 官方下载地址- load -i dm8****.tar (注意修改为当前下载的文件)达梦官方文档注意修改为当前版本 docker run -d -p 5236:5236 --name dm8 --privilegedtrue -…

程序员口才提升技巧:从技术到沟通的进阶之路

程序员口才提升技巧&#xff1a;从技术到沟通的进阶之路 在数字化时代&#xff0c;程序员作为推动技术发展的关键角色&#xff0c;其专业能力的重要性不言而喻。然而&#xff0c;除了编程技能外&#xff0c;良好的口才同样是程序员职业生涯中不可或缺的一部分。本文将探讨程序…

学透Spring Boot — [二] Spring 和 Spring Boot的比较

欢迎关注我们的专栏 学透 Spring Boot 一、创建一个简单Web应用 本篇文章&#xff0c;我们将会比较 Spring 框架和 Spring Boot 的区别。 什么是 Spring? 也许你在项目中已经可以很熟练的使用 Spring 了&#xff0c;但是当被问到这个问题时&#xff0c;会不会犹豫一下&#…

2024-3-28 市场情绪强修复

这一轮退潮负反馈都修复了&#xff0c; 艾艾精工 博信股份 安奈尔 永悦科技 大理药业 &#xff0c;高新发展 也补跌了&#xff0c;收尸队也干活了&#xff0c;情绪不修复不接力得最好写照。这轮周期 宁科生物 已经7板&#xff0c;已经追平了 博信股份7板&#xff0c;看明天溢…

永磁同步电机速度环滑膜控制(SMC)

文章目录 1、前言2、滑膜控制基本原理2.1 滑膜控制的定义2.2 趋近率 3、滑膜控制器的设计与参数4、二阶滑膜速度控制器的设计5、二阶速度环滑膜控制仿真5.1 模型总览5.2 电机及系统参数5.3 滑膜控制模块5.4 控制效果对比 参考 写在前面&#xff1a;本人能力、时间、技术有限&am…

广场舞团系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. 系…

明天线上见!DPU构建高性能云算力底座——DPU技术开放日最新议程公布!

算力&#xff0c;是数字经济时代的新质生产力。随着人工智能、智算中心建设等需求不断拓展&#xff0c;DPU在各行各业数据中心的应用逐步深入。异构算力代表DPU在新质生产力建设中&#xff0c;能否给出别开生面的答案&#xff0c;应战算力难题&#xff1f;DPU技术在不同行业中的…

详细解析记忆泊车的顶层技术原理

详细解析记忆泊车的顶层技术原理 附赠自动驾驶学习资料和量产经验&#xff1a;链接 相对于记忆行车而言&#xff0c;记忆泊车 MPA&#xff08;Memory Parking Assist&#xff09;可以看成是停车场区域内的一个自动驾驶功能&#xff0c;可帮助用户按记忆的路线自动巡航并泊入车…

Vue2 与 Vue3的面试题

1.Promise有几种状态 pending(进行中) fulfilled(已成功) rejected(已失败) data(){return{}},create(){const result this.ganaretor()result.next.value.then((res)>{console.log(res);}) // 解决一直.then()方法问题},methods:{* ganaretor(){yield axios.get(httpts)…

vulnhub靶场之driftingblues-3

一.环境搭建 1.靶场描述 get flags difficulty: easy about vm: tested and exported from virtualbox. dhcp and nested vtx/amdv enabled. you can contact me by email for troubleshooting or questions. This works better with VirtualBox rather than VMware 2.靶场…
最新文章