c++學習之---模版

?

目錄

一、函數模板:

? ? ? ? 1、基本定義格式:

? ? ? ? 2、模版函數的優先匹配原則:

二、類模板:????????

? ? ? ? 1、基本定義格式:

????????2、類模版的優先匹配原則(有坑哦):

????????3、缺省值的設置:

????????4、typename關鍵字(參數名稱的迷惑性):

????????5類模版里的函數模版:

三、非類型模板參數:

? ? ? ? 1、基本定義格式:

????????2、c++里的array:

????????3、缺省值規則的貓膩:

四、模版的特化:

1、函數模板的特化:? ? ? ??

2、類模板的特化:?

? ? ? ? 全特化:

????????偏特化:

? ? ? ? 進一步對指針和引用的偏特化:

五、模版的聲明定義分離---危!!!

????????1、顯式聲明:

????????2、都擠在頭文件算了:

? ? ? ? 3、模板無法直接聲明和定義分離的原理:

六、一點邊角料:

????????1,類模版的按需實例化:

????????2,頭文件之間交叉引用所要注意的小細節:


? ? ? ? 模版,物如其名 。?就是個類似于設計圖紙似的東西,有了圖紙,我們就可以在此基礎上添枝加葉后較為輕松的做出成品;

? ? ? ? c++里的模板也是相同的道理,有了模板,在此基礎上就可以衍生出各種不同的成品(函數和類)。

一、函數模板:

? ? ? ? 1、基本定義格式:

? ? ? ? 定義一個函數模版需要用到的關鍵字是 template? , 然后結合class 或 typename就可以達到定義模版參數的效果。如下:

template<class T>  //定義格式:template開頭,用尖括號包圍,里面用class搭配上形參名(比如此處的T)
// template<typename T>  //typename 和class在此時沒有區別//這里函數中涉及相關類型的地方用模版參數T替代了T multiple(T left, T rigTht)
{return left * right;
}

? ? ? ? 2、模版函數的優先匹配原則:

? ? ? ? ? ?雖然上面我們提到模版的一大本質在于讓編譯器根據函數傳參的具體類型在編譯階段生成帶有具體類型的函數,但編譯器只是勤快,而不是傻!!!如果已經有了現成的函數,他就直接調用這個函數,而非吭哧吭哧的埋頭苦干....

? ? ? ? 當調用一個函數時,如果已經存在現成的函數版本,編譯器則會直接調用它,而不是自己另外生成.

//具體類型的函數定義
int multiple(int left, int right)
{return left * right;
}
//模版函數定義
template<class T>
T multiple(T left, T rigTht)
{return left * right;
}//調用語句里傳入了兩個整形值
cout << multiple(1, 2) << endl;

? ? ? ? 下面是通過調試觀察到了程序運行時的情況?

二、類模板:????????

? ? ? ? 1、基本定義格式:

? ? ? ? 類模版的定義方式和函數模版類似,同樣關鍵字template、<>、class或typename的組合,只不過作用的范圍是緊隨其后的整個類,整個類里的變量和函數里凡是涉及到類型的地方都可以使用一開始定義的模版參數

template<class T>
class myclass
{
public:T add(T val)  //成員函數的返回值和形參使用模版參數類型{T tmp = 0; //函數內部也可以使用模版參數類型return _val1 + _val2 + val;}
private:T _val1; //成員變量使用模版參數類型T _val2;
};

????????2、類模版的優先匹配原則(有坑哦):

? ? ? ? 模版的匹配原則起始挺傻瓜的,畢竟在真正實例化出具體的類型之前,編譯器能看到有幾個參數,以及是否相同和順序如何(從左往右匹配)。

? ? ? ? 下面用一個模擬實現vector成員函數的例子來闡釋:

// 用n 個 val初始化的構造函數
vector(int num, const T& val):_start(new T[num])
{for (int i = 0; i < num; i++){*(_start + i) = val;}_finish = _end_of_storage = _start + num;
}
// 用迭代器區間初始化的構造函數
template<class inputIterator>
vector(inputIterator begin, inputIterator end)
{while (begin != end){push_back(*begin);begin++;}
}

? ? ? ? ?如果只存在以上兩種vector的構造函數,那么當使用這樣的語句來實例化一個對象時,就會報錯 :vector<int> v(5,7)。也就是傳遞兩個整形值,下面是分析:

? ? ? ? 最簡單的解決方法是自己另外寫一個更加明顯的版本:把int改為size_t ,這樣一來,參數6會被隱式類型轉換為size_t,參數9仍然是正常的int ,但正因如此,就變成了參數類型不同的函數,也就能和第二個函數完美的區分開來。

????????3、缺省值的設置:

? ? ? ? 類似于函數重載,類模版也可以設置缺省值。比較常用的情景就是在為容器適配器設置默認的底層容器,比如stack和queue底層的deque :

? ? ? ? 這樣即使在創建stack或者queue的對象時,沒有特殊情況的話就只是顯式實例化一個模版參數,比如myStack<int>就可以并不需要繁瑣的myStack<int,deueue<T>>

template<class T , class Container = deque<T>>
class myStack()
{//stack類的相關實現.............
}template<class T , class Container = deque<T>>
class myQueue()
{//queue類的相關實現
..................
}

????????4、typename關鍵字(參數名稱的迷惑性):

? ? ? ? 都學習過函數的我們知道,函數的形參的名稱真的就只是一個普通的名稱,僅僅是為了方便內部的使用,甚至不寫形參的名字在語法上也是對的。

????????c++在運算符重載里區分前置和后置的++和--時就利用了這一點,如下圖就是一個日期類的后置++的成員函數:

Date operator++(int)  // int參數僅用于區分前置/后置++,因此壓根就不用寫形參名
{  Date temp = *this; *this = *this + 1; return temp;        
}

?????????下面通過一個printf_container,也就是通用的容器打印函數,來說明形參名稱的迷惑性(模版參數的形參也是形參,只不過不向函數的形參那樣可以省略罷了)。

template<class Container>
void PrintContainer(const Container& obj)
{Container::iterator it = obj.begin();  //這條語句又隱藏的風險while(it != obj.end()){cout << *it <<" ";it++;}
}

? ? ? ? 這里的問題的根源在于程序員和編譯器視角的不同:

  • 在我們心中,這里的Container代表各種容器,因此函數里的 Container::Iterator it 的寫法是順理成章的.
  • 可是在編譯器眼里, 這里的Container僅僅只是一個類型名,雖然可能是容器類型(自定義類型) , 但同樣也可能是int、double等內置類型。
  • 編譯器的做法很嚴謹,為了避免函數在被調用時,參數實例化為了int等內置類型,就在編譯階段進行攔截了?。畢竟,int::iterator it 這樣的語句怎么看怎么逆天...
  • 這個問題的解法,是typename關鍵字,顯式的告訴編譯器這是一個類。或者更省心一點,直接用關鍵字auto來讓編譯器自己推導正確的類型。
//正確的寫法
template<class Container>
void PrintContainer(const Container& obj)
{//關鍵代碼
//------------------------------------------------------------------------------------typename Container::const_iterator it = obj.begin();  //在前面加上typename關鍵字//auto iterator it = obj.begin();                     //當然auto就更省心啦
//---------------------------------------------------------------------------------------while (it != obj.end()){cout << *it << " ";it++;}
}

????????5類模版里的函數模版:

? ? ? ? 一個類的內部并非只能使用在類之前定義的那些模版參數,也就是說:一個類的成員函數還可以定義自己的模版參數。

template<class T>
class myclass
{
public://特立獨行的成員函數add,定義了自己的模版參數
//--------------------------------------------------------------template<class Y>Y add(Y val){return _val1 + _val2 + val;}
//-----------------------------------------------------------------
private:T _val1;T _val2;
};

三、非類型模板參數:

? ? ? ? 1、基本定義格式:

? ? ? ? 定義模版類型時,我們既可以用關鍵字class和typename來定義一個通用的類型,反過來,我們也可以直接寫死所期望的類型,比如下面這個例子里:一個成員變量為array類型的類,在模版參數里固定了整形變量,甚至是他的缺省值。


template<class T , int size = 10>   //此處的int size就是非類型模版參數,10是他的缺省值
class Array
{
public:Array(){double tmp = 1.2;for (auto& au : obj){au = (tmp += 3.9);}}void PrintSelf(){for (auto au : obj){cout << au << " ";}cout << endl;}
private:array<T, size> obj;           //size也就充當了array類型對象的元素個數
};

????????2、c++里的array:

? ? ? ? 在上面對于非類型模版參數的例子中,我使用到了c++里的一個不太起眼的容器——array。看名字咱就很眼熟,誰在初學c語言數組的時候不是這樣定義的數組名稱??? int arr[10] ={0}

????????其實array的底層就是一個靜態數組,只不過還夾帶了一點私貨,讓他比普通的靜態數組更加安全和好用。

普通的靜態數組封裝了靜態數組的容器array
安全性僅僅在空間的邊界處設有標志位一旦越界訪問,斷言報錯
便捷性需要自己寫for循環遍歷支持迭代器遍歷
可讀性int arr [10]中 int [10]才是類型名array<int,10> obj 中 obj之前的就是類型名

? ? ? ? ?順帶補充一點:普通靜態數組的越界檢查比較簡陋,主要就是在底層封裝了一層邏輯來判斷內存邊界前后的元素是否被修改,這也代表如果只是訪問元素,幾遍非法,也不會報錯。看下面的情況:

????????3、缺省值規則的貓膩:

? ? ? ? 非類型模版的規則隨著c++標準的迭代經歷了巨多巨多的變更,如下圖所示。看看就好,不用太在意,需要用的時候查資料就好啦。

標準版本整型/枚舉指針/引用浮點類型類類型其他特性
C++98/03??????-
C++11/14??????nullptr?支持
C++17??????auto?推導
C++20????????(字面量類)字符串字面量間接支持
C++23????????結構化綁定

四、模版的特化:

? ? ? ? 模版的特化,無論是函數模版還是類模版,都是在原有模版的基礎上進行的更加具象化的定義,因此特化后的模版參數起碼在參數個數上要和原模版相匹配!!!

1、函數模板的特化:? ? ? ??

? ? ? ?特化就是對全部的模版參數特殊處理化

//函數模版的基礎版本
template<class T , class Y>
Y add(T left, Y right)
{return left + right;
}
//函數模版的全特化版本
template<>      //由于是全特化,所以不再使用原來的模版參數,這里可以空著
double add<int,double>(int left, double right)  //寫法的關鍵在于函數名之后、括號之前顯示實例化 模版參數(類似于定義模版類對象時的寫法);以及,替換模版參數為具體的類型。
{return left + right;
}

2、類模板的特化:?

? ? ? ? 全特化:

//基礎的類模板
template<class T ,class Y>
class Myclass
{
public:
private:T _val1;Y _val2;
};
//全特化的類模板
template<>   //全特化就可以把這里空著,因為全部要自己顯式寫
class Myclass<int, double>  //顯式實例化(注意模板參數個數要和原模板一致)
{
public:
private:int _val1;double _val2;
};

????????偏特化:

//基礎的類模板
template<class T ,class Y>
class Myclass
{
public:
private:T _val1;Y _val2;
};
//偏特化的類模板
template<class T>    //這里偏特化模板參數Y,所以原來的參數T還得寫
class Myclass<T,double>   //顯式實例化時僅僅將偏特化的模板參數確定即可
{
public:
private:T _val1;double _val2;
};

? ? ? ? 進一步對指針和引用的偏特化:

? ? ? ? 偏特化除了可以理解為“對一部分模板參數特殊處理化”之外,也有“對已有的模板參數進一步處理”的功能。

//原模板
template<class T ,class Y>
class Myclass
{
public:
private:T _val1;Y _val2;
};
//偏特化出指針類型
template<class T, class Y>
class Myclass<T*, Y* >
{
public:
private:T _val1;Y _val2;
};
//偏特化出引用類型
template<class T, class Y>
class Myclass<T& ,Y& >
{
public:
private:T _val1;Y _val2;
};

五、模版的聲明定義分離---危!!!

? ? ? ? c、c++是典型的編譯型語言,中途會把每個源文件獨立編譯,最后和頭文件一起鏈接起來生成可執行文件。因此但凡是寫過小項目的人,一定會用到聲明和定義分離的項目組織模式。

? ? ? ? 但是 ,當編寫的函數或者類使用到了模板,卻仍然像效仿c語言那樣直接將聲明和定義分離的話必定會看到撲朔離奇的報錯,下面給出常用的解決方案以及背后所蘊含的原理。

????????1、顯式聲明:

  1. ?實在是要聲明和定義分離,就必須在源文件里顯式特化,也就是給出具體的類型。
  2. ?這樣的做法不實用?:傳入的參數的類型可能有很多,一旦是沒有顯示特化的類型,依然會報錯,但是程序員難免會有疏忽導致沒有提前謀劃好此函數可能接受的所有參數類型,從而出現問題。
  3. 建議在源文件里依然不辭勞苦的寫一份原模板函數,這時c++標準的一項規定。有趣的是:如果在源文件里不寫源模板函數,僅僅是顯示特化的版本,編譯器會警告,但仍然會正常運行......。
  4. 第三點中的現象的原因在于:編譯器對模板的處理分兩部分,一是在編譯階段檢查基本的語法,此時發現一個聲明后面沒有定義,但由于每個文件都是單獨編譯,編譯器不能排除定義放在其他文件的可能性,所以沒有攔截我們;二是在鏈接時編譯器找到了其他源文件里顯示特化后直接可用的函數版本,所以就一路長虹的執行下去嘍,最后造成了有警告但沒報錯的奇異現象。
//.h 文件的聲明
template<class T>
void testFunc(T a);//.c文件的顯式特化//保留初始版本的函數模版   
template<class T>
void testFunc(T a)
{		cout << a << endl;
}
//特化版本
template<>
void testFunc<int>(int a)
{cout << a << endl;
}

????????2、都擠在頭文件算了:

? ? ? ? 既然聲明和定義分離有陷阱,那干脆放棄掙扎,直接都放在頭文件里算了

????????類里的成員函數在聲明時就順便定義:類里的代碼量較小成員函數默認會作為內聯函數,代碼量較大的函數則會和普通函數一樣進入符號表后參與編譯的過程。?

? ? ? ? 3、模板無法直接聲明和定義分離的原理:

? ? ? ? 這個就要從c、c++這種編譯型語言的可執行文件生成階段說起了,分別是:預處理、編譯、匯編、鏈接。

  1. 預處理:展開頭文件、去掉注釋、進行宏替換、執行條件編譯。
  2. 編譯 : 分別對每個源文件單獨進行詞法語法分析、生成匯編代碼。此階段中,頭文件里的模板函數或類的聲明不會被編譯器是做毒瘤,因為有可能具體實現在其他文件里,要等到鏈接的時候才能下定論;源文件里的模板函數或類由于尚未被調用,沒有實例化出具體的代碼,也就沒有進入符號表,無法被找到。
  3. 匯編:將匯編代碼轉換為CPU可以直接執行的二進制代碼。
  4. 鏈接:將所有源文件和頭文件連接,生成可執行程序。此時編譯器發現模板類和模板函數不存在于符號表,也無法確定調用的地址,所以報錯。

????????

六、一點邊角料:

????????1,類模版的按需實例化:

? ? ? ? 模版僅僅是一個模具、一份設計圖紙,就像各種武器還僅僅是一份概念圖而尚未被制造出來時不會別別的國家所忌憚,當然,更多的時候壓根就沒人知道。

? ? ? ? 因此編譯器就好像是一個不知道鄰國正在研發秘密武器的懵懵懂懂的總統,在鄰國的武器制造出來之前,即模版實例化具體的類或者函數之前,都不太會引起總統/編譯器的注意。

? ? ? ? 說人話就是:只要不調用某個類的成員函數,即便這個成員函數內部存在一些荒唐的邏輯錯誤(比如使用了不存在的函數),也不會報錯!!!

//類模版
template<class T , int size = 10>
class Array
{
public:void SecretWeapon(){obj.push_back(666); //成員變量obj是array<T,size>類型,容器array顯然沒有push_back接口}
private:array<T, size> obj;
};

?

????????2,頭文件之間交叉引用所要注意的小細節:

? ? ? ?在一個源文件里包含其他頭文件是十分常見的操作,但是在c++里也會有一些和命名空間有關的坑,如下是一個頭文件和一個源文件以及程序運行的報錯結果:

//頭文件 extend.htemplate<class T>
class MyClass
{
public:void Print(){cout << buddy; //這里用到了<iostream>庫,std命名空間里的cout函數!!!}
private:int buddy = 100;
};
//源文件 Main.c#include<iostream>
#include"extend.h"    //包含了我們自己的頭文件"extend.h",其中有用的官方庫的cout函數
using namespace std;int main()
{cout << "good morning , my dear boY !!!" << endl;return 0;
}

? ? 這樣就很奇怪,畢竟我們既包含了官方庫(#include<iostream>) , 也展開了命名空間(using namespace std) , 可編譯器還是無法找到我們頭文件里的cout函數 . 其實問題就出現在源文件里那幾條語句的聲明順序!!!

? ? ? ? 對于在源文件里包含一個頭文件,不要感到恐慌.當程序在運行之前,首先要進行預處理,這里就是出現問題的關鍵,下面就是我程序們的預處理之后大致的模樣 : 可以看到原先的#include"extend.h"這一句指令被替換成了頭文件里的代碼

#include<iostream>
//------------------------------下面是頭文件"extend.h"展開之后的樣子
template<class T>
class MyClass
{
public:void Print(){cout << buddy;}
private:int buddy = 100;
};
----------------------------------上面是頭文件"extend.h"展開之后的樣子
using namespace std;int main()
{cout << "good morning , my dear boY !!!" << endl;return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85424.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85424.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85424.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringAI(GA):RAG下的ETL快速上手

原文鏈接&#xff1a;SpringAI(GA)&#xff1a;RAG下的ETL快速上手 教程說明 說明&#xff1a;本教程將采用2025年5月20日正式的GA版&#xff0c;給出如下內容 核心功能模塊的快速上手教程核心功能模塊的源碼級解讀Spring ai alibaba增強的快速上手教程 源碼級解讀 版本&a…

用dayjs解析時間戳,我被提了bug

引言 前幾天開發中突然接到測試提的一個 Bug&#xff0c;說我的時間組件顯示異常。 我很詫異&#xff0c;這里初始化數據是后端返回的&#xff0c;我什么也沒改&#xff0c;這bug提給我干啥。我去問后端&#xff1a;“這數據是不是有問題&#xff1f;”。后端答&#xff1a;“…

DataAgent產品經理(數據智能方向)

DataAgent產品經理&#xff08;數據智能方向&#xff09; 一、核心崗位職責 AI智能體解決方案設計 面向工業/政務場景構建「數據-模型-交互」閉環&#xff0c;需整合多源異構數據&#xff08;如傳感器數據、業務系統日志&#xff09;與AI能力&#xff08;如大模型微調、知識圖…

Ubuntu取消開機用戶自動登錄

注&#xff1a;配置前請先設置登錄密碼&#xff0c;不同顯示管理器配置方法不同&#xff0c;可用命令查看&#xff1a;cat /etc/X11/default-display-manager 一、LightDM 顯示管理器&#xff0c;關閉 Ubuntu 系統用戶自動登錄 查找自動登錄配置文件&#xff0c;可以看到類似 a…

使用lighttpd和開發板進行交互

文章目錄 &#x1f9e0; 一、Lighttpd 與開發板的交互原理1. 什么是 Lighttpd&#xff1f;2. 與開發板交互的方式&#xff1f; &#x1f9fe; 二、lighttpd.conf 配置文件講解?? 注意事項&#xff1a; &#x1f4c1; 三、目錄結構說明&#x1f4a1; 四、使用 C 編寫 CGI 腳本…

Apache IoTDB V2.0.3 發布|新增元數據導入導出腳本適配表模型功能

Release Announcement Version 2.0.3 Apache IoTDB V2.0.3 已經發布&#xff01; V2.0.3 作為樹表雙模型正式版本&#xff0c;主要新增元數據導入導出腳本適配表模型、Spark 生態集成&#xff08;表模型&#xff09;、AINode 返回結果新增時間戳&#xff0c;表模型新增部分聚…

車輛檢測算法在爆炸事故應急響應中的優化路徑

視覺分析賦能車輛管控&#xff1a;以山東應急場景為例 背景&#xff1a;應急場景下的車輛管控痛點 近期山東多起爆炸事故暴露了應急響應中的車輛管理短板&#xff1a;消防車、救護車因違停車輛堵塞通道&#xff0c;違規車輛闖入事故核心區&#xff0c;傳統監控系統依賴人工識別…

∑ 1/n 調和級數 是 發散的

為什么 ∑ 1 u \sum \frac{1}{u} ∑u1?&#xff08;即 ∑ 1 n \sum \frac{1}{n} ∑n1?&#xff0c;通常稱為調和級數&#xff09;是發散的&#xff1f; ? 一、首先明確你問的是這個級數&#xff1a; ∑ n 1 ∞ 1 n \sum_{n1}^{\infty} \frac{1}{n} n1∑∞?n1? 這個級數…

Android第十二次面試-多線程和字符串算法總結

多線程的創建與常見使用方法 ?一、多線程創建方式? ?1. 繼承Thread類? class MyThread extends Thread {Overridepublic void run() {// 線程執行邏輯System.out.println(Thread.currentThread().getName() " is running");} }// 使用 MyThread thread new …

大模型調用數據庫表實踐:基于自然語言的SQL生成與數據查詢系統

# 大模型調用數據庫表實踐&#xff1a;基于自然語言的SQL生成與數據查詢系統 ## 一、背景與目標 在企業數據管理場景中&#xff0c;非技術人員&#xff08;如業務人員、管理人員&#xff09;常常需要通過數據庫查詢獲取關鍵信息&#xff0c;但直接編寫SQL語句存在技術門檻。傳…

28 C 語言作用域詳解:作用域特性(全局、局部、塊級)、應用場景、注意事項

1 作用域簡介 作用域定義了代碼中標識符&#xff08;如變量、常量、數組、函數等&#xff09;的可見性與可訪問范圍&#xff0c;即標識符在程序的哪些位置能夠被引用或訪問。在 C 語言中&#xff0c;作用域主要分為三類&#xff1a; 全局作用域局部作用域塊級作用域 需注意&am…

Tomcat運行比較卡頓進行參數調優

在Tomcat conf/catalina.bat或catalina.sh中 的最上面增加參數 1. 初步調整參數&#xff08;緩解問題&#xff09; set JAVA_OPTS -Xms6g -Xmx6g -Xmn3g # 增大新生代&#xff0c;減少對象過早晉升到老年代 -XX:MetaspaceSize256m -XX:MaxMetaspaceS…

WSL2 安裝與Docker安裝

注意&#xff1a;如沒有科學上網請勿嘗試&#xff0c;無法判斷是否會因網絡錯誤導致的安裝失敗&#xff01;&#xff01;&#xff01; WSL2&#xff08;Windows Subsystem for Linux 2&#xff09; 功能簡介&#xff1a; WSL2 是微軟提供的在 Windows 上運行完整 Linux 內核的…

Redis的安裝與使用

網址&#xff1a;Spring Data Redis 安裝包&#xff1a;Releases tporadowski/redis GitHub 解壓后 在安裝目錄中打開cmd 打開服務&#xff08;注意&#xff1a;每次客戶端連接都有先打開服務&#xff01;&#xff01;&#xff01;&#xff09; 按ctrlC退出服務 客戶端連接…

springboot-響應接收與ioc容器控制反轉、Di依賴注入

1.想將服務器中的數據返回給客戶端&#xff0c;需要在controller類上加注解&#xff1a;ResponseBody; 這個注解其實在前面已經使用過&#xff0c;RestController其實就包含兩個注解&#xff1a; Controller ResponseBody 返回值如果是實體對象/集合&#xff0c;將會轉換為j…

將材質球中的紋理屬性對應的貼圖保存至本地

通過Texture2D的EncodeToPNG方法將紋理轉為圖片形式 material.GetTexture方法通過屬性名獲取紋理貼圖 material.SetTexture方法通過屬性名設置紋理貼圖 屬性名可在shader代碼中查看 using UnityEngine; using System.IO;public class TextureSaver : MonoBehaviour {public…

MySQL半同步復制配置和參數詳解

目錄 1 成功配置主從復制 2 加載插件 3 半同步復制監控 4 半同步復制參數 1 成功配置主從復制 操作步驟參考&#xff1a;https://blog.csdn.net/zyb378747350/article/details/148309545 2 加載插件 #主庫上 MySQL 8.0.26 之前版本: mysql>INSTALL PLUGIN rpl_semi_syn…

【筆記】Windows 成功部署 Suna 開源的通用人工智能代理項目部署日志

#工作記錄 本地部署運行截圖 kortix-ai/suna&#xff1a; Suna - 開源通用 AI 代理 項目概述 Suna 是一個完全開源的 AI 助手&#xff0c;通過自然對話幫助用戶輕松完成研究、數據分析等日常任務。它結合了強大的功能和直觀的界面&#xff0c;能夠理解用戶需求并提供結果。其強…

PCB制作入門

文章目錄 1 嘉立創使用旋轉 2元器件選擇MP2315SLM7815與LM7915 1 嘉立創使用 旋轉 空格旋轉 2元器件選擇 MP2315S MP2315S 是一款內置功率 MOSFET 的高效率同步整流降壓開關變換器。 其輸入電壓范圍為 4.5V 至 24V &#xff0c;能實現 3A 連續輸出電流&#xff0c;負載與…

2025——》NumPy中的np.logspace使用/在什么場景下適合使用np.logspace?NumPy中的np.logspace用法詳解

1.NumPy中的np.logspace使用: 在 NumPy 中,np.logspace函數用于生成對數尺度上等間距分布的數值序列,適用于科學計算、數據可視化等需要對數間隔數據的場景。以下是其核心用法和關鍵細節: 一、基礎語法與參數解析: numpy.logspace(start, stop, num=50, endpoint=True, ba…