欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++11中可變模板參數(shù)的實(shí)現(xiàn)

 更新時(shí)間:2024年12月23日 08:34:34   作者:我太想進(jìn)步了??!  
C++11的可變參數(shù)模板允許創(chuàng)建可以接受可變參數(shù)的函數(shù)和類模板,通過遞歸展開參數(shù)包來處理每個(gè)參數(shù),下面就來介紹一下,感興趣的可以了解一下

C++11的新特性可變參數(shù)模板能夠讓您創(chuàng)建可以接受可變參數(shù)的函數(shù)模板和類模板,相比 C++98/03,類模版和函數(shù)模版中只能含固定數(shù)量的模版參數(shù),可變模版參數(shù)無疑是一個(gè)巨大的改 進(jìn)。

像之前學(xué)習(xí)的printf就是一個(gè)函數(shù)參數(shù)的可變參數(shù),它可以接收多個(gè)任意類型,但它們只函數(shù)參數(shù)的可變參數(shù),并不是模板的可變參數(shù)

printf的使用方法:

int printf( const char *format , ... );

本博客講解的是函數(shù)模板的可變參數(shù),不會涉及到類模板的可變參數(shù)

可變模板的定義方式

函數(shù)的可變參數(shù)模板定義方式如下:

template<class ...Args> //Args全稱:arguments
返回類型 函數(shù)名(Args... args)
{
    //函數(shù)體
}

下面就是一個(gè)基本可變參數(shù)的函數(shù)模板

template <class ...Args>
void ShowList(Args... args)
{}

Args:是一個(gè)可變模板參數(shù)包

args:是一個(gè)函數(shù)形參參數(shù)包

說明一下:

模板參數(shù)Args前面有省略號,代表它是一個(gè)可變模板參數(shù),我們將帶省略號的參數(shù)稱為 “參數(shù)包”,這個(gè)參數(shù)包中可以包含0到任意個(gè)模板參數(shù),args則是一個(gè)函數(shù)形參參數(shù)包

現(xiàn)在我們可以向這個(gè)函數(shù)中傳入多個(gè)不同的類型,并且可以通過sizeof算出參數(shù)包的參數(shù)個(gè)數(shù)

以下例代碼為例:

template<class ...Args>
void ShowList(Args... args)
{
	cout << sizeof...(args) << endl;
}


int main()
{
	ShowList(1);
	ShowList(1, 2);
	ShowList(1, 2, string("dict"));
	map<string, int> m1;
	ShowList(1, 2, 3, m1);

	return 0;
}

我們無法直接獲取參數(shù)包args中的每個(gè)參數(shù)的, 只能通過展開參數(shù)包的方式來獲取參數(shù)包中的每個(gè)參數(shù),這是使用可變模版參數(shù)的一個(gè)主要特點(diǎn),也是最大的難點(diǎn),即如何展開可變模版參數(shù)。

由于C++11語法不支持使用args[i]這樣方式獲取可變q參數(shù),所以我們的用一些奇招來一一獲取參數(shù)包的值。

錯(cuò)誤示例:

template<class ...Args>
void ShowList(Args... args)
{
	//error
	for (int i = 0; i < sizeof...(args); ++i)
	{
		cout << args[i] << endl;
	}
}

參數(shù)包的展開方式

遞歸的方式展開參數(shù)包

方式如下:

1.給函數(shù)模板新增一個(gè)參數(shù),這樣就可以從接收到的參數(shù)包分離出來一個(gè)參數(shù)

2.在函數(shù)模板中進(jìn)行遞歸,不斷的分離參數(shù)包中的參數(shù)

3.直到接收到最后一個(gè)參數(shù)結(jié)束

結(jié)束條件;

->1. 可以創(chuàng)建一個(gè)無參的函數(shù)來終止遞歸:當(dāng)參數(shù)包中的參數(shù)為0時(shí)會調(diào)用該函數(shù)終止循環(huán)

void _ShowList()
{
	cout << endl;
}

template<class T, class ...Args>
void _ShowList(T value, Args... args)
{
	cout << value << ' ';
	_ShowList(args...);
}

int main()
{
	_ShowList(1, 2, string("dict"));

	return 0;
}

->2. 可以創(chuàng)建一個(gè)參數(shù)的函數(shù)來終止遞歸:當(dāng)參數(shù)包中的參數(shù)為1時(shí)會調(diào)用該函數(shù)終止循環(huán)

template<class T>
void _ShowList(const T& t)
{
	cout << t << endl;
}

template<class T, class ...Args>
void _ShowList(T value, Args... args)
{
	cout << value << ' ';
	_ShowList(args...);
}

int main()
{
	_ShowList(1, 2, string("dict"));

	return 0;
}

但是使用該方法有一個(gè)弊端:我們在調(diào)用ShowList函數(shù)時(shí)必須至少傳入一個(gè)參數(shù),否則就會報(bào)錯(cuò),因?yàn)榇藭r(shí)無論是調(diào)用遞歸終止函數(shù)還是展開函數(shù),都需要至少傳入一個(gè)參數(shù)

使用sizeof...(args)算出參數(shù)個(gè)數(shù)的特性,利用它的特性做一個(gè)遞歸結(jié)束條件可以嗎?不行!

template<class T, class ...Args>
void ShowList(T value, Args... args)
{
	cout << value << ' ';
	if (sizeof...(args))
	{
		return;
	}
	ShowList(args...);
}

函數(shù)模板并不能調(diào)用,函數(shù)模板需要在編譯時(shí)根據(jù)傳入的實(shí)參類型進(jìn)行推演,生成對應(yīng)的函數(shù),這個(gè)生成的函數(shù)才能夠被調(diào)用。
而這個(gè)推演過程是在編譯時(shí)進(jìn)行的,當(dāng)推演到參數(shù)包args中參數(shù)個(gè)數(shù)為0時(shí),還需要將當(dāng)前函數(shù)推演完畢,這時(shí)就會繼續(xù)推演傳入0個(gè)參數(shù)時(shí)的ShowList函數(shù),此時(shí)就會產(chǎn)生報(bào)錯(cuò),因?yàn)镾howList函數(shù)要求至少傳入一個(gè)參數(shù)。
這里編寫的if判斷是在代碼編譯結(jié)束后,運(yùn)行代碼時(shí)才會所走的邏輯,也就是運(yùn)行時(shí)邏輯,而函數(shù)模板的推演是一個(gè)編譯時(shí)邏輯。

還有一種特殊的方式,該方法比較抽象,就是使用逗號表達(dá)式展開參數(shù)包

->3. 逗號表達(dá)式展開參數(shù)包

template<class T>
void CPPprint(const T& value)
{
	cout << value << ' ';
}

template<class ...Args>
void ShowList(Args... args)
{
	int array[] = {( CPPprint(args), 0)...};
	cout << endl;
}

當(dāng)我們在數(shù)組中不標(biāo)注元素個(gè)數(shù)時(shí),編譯器會幫我們自動推導(dǎo)元素個(gè)數(shù),這時(shí)它會幫我們展開參數(shù)包

如下:

int array[] = {( CPPprint(args), 0), CPPprint(args), 0),  CPPprint(args), 0),  CPPprint(args), 0)};

在調(diào)用CPPprint函數(shù)的同時(shí),利用逗號運(yùn)算符的特性進(jìn)行對數(shù)組的初始化

其實(shí)也可以不使用逗號運(yùn)算符完成該操作

template<class T>
int CPPprint(const T& value)
{
	cout << value << ' ';
	return 0;
}

template<class ...Args>
void ShowList(Args... args)
{
	int array[] = { (CPPprint(args))... };
	cout << endl;
}

將被調(diào)用的函數(shù)設(shè)置一個(gè)返回值,調(diào)用之后返回0,這樣就可以在編譯器展開參數(shù)包調(diào)用函數(shù)時(shí),通過返回值初始化

STL中的emplace相關(guān)接口函數(shù)

以便大家更好的理解emplace,先給大家看一段代碼,可變模板參數(shù)的使用場景:

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Data()~構(gòu)造函數(shù)" << endl;
	}

	Date(const Date& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "Date()~拷貝構(gòu)造" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

template<class ...Args>
Date* Init(Args&&... args)
{
	Date* ret = new Date(args...);

	return ret;
}

int main()
{
	Date* p1 = Init();
	Date* p2 = Init(2024);
	Date* p3 = Init(2024, 11);
	Date* p4 = Init(2024, 11, 12);

	Date d1(2, 3, 3);
	Date* p5 = Init(d1);
	return 0;
}

我們通過將參數(shù)傳入?yún)?shù)包在編譯期間通過將參數(shù)包展開的操作進(jìn)行對象的構(gòu)造

STL容器中emplace相關(guān)插入接口函數(shù)

C++11標(biāo)準(zhǔn)STL中的容器增加emplace版本的插入接口,比如list容器的push_front,push_back和insert函數(shù),都增加了對應(yīng)的emplace_front,emplace_back,emplace函數(shù)。如下:

emplace接口全部都是使用的可變參數(shù)模板

注意:兩個(gè)&&是萬能引用并不是右值引用

對比list中的push_back和emplace_back,對于emplace系列接口而言,它的主要優(yōu)勢就是直接在容器內(nèi)部構(gòu)造元素可以結(jié)合我上面給的場景進(jìn)行理解,而不是構(gòu)造一個(gè)臨時(shí)對象在復(fù)制或移動到容器中可以有效的避免拷貝和移動操作

以emplace和push_back為例:

調(diào)用push_back函數(shù)插入元素時(shí),可以傳入左值對象或者右值對象,也可以使用列表初始化

調(diào)用emplace時(shí)可以傳左值對象或者右值對象,但是不能使用列表初始化,emplace系列最大的特點(diǎn)就是,插入元素時(shí)可以傳入用于構(gòu)造元素的參數(shù)包

比如:

int main()
{
	list<pair<nxbw::string, int>> mylist;
	pair<nxbw::string, int> kv("nxbw", 10);
	mylist.emplace_back(kv); //傳左值
	mylist.emplace_back(make_pair("nxbw", 10)); //傳右值
	mylist.emplace_back("nxbw", 10); //傳參數(shù)包

	mylist.push_back(kv); //傳左值
	mylist.push_back(make_pair("nxbw", 10)); //傳右值
	mylist.push_back({ "nxbw", 10 }); //使用列表初始化

	return 0;
}

原地構(gòu)造:使用emplace,你可以提供構(gòu)造元素所需的參數(shù),容器會直接在emplace接口的實(shí)現(xiàn)中構(gòu)造該對象

emplace系列接口的工作流程

emplace系列接口的工作流程如下:

  • 先通過空間配置器為新結(jié)點(diǎn)獲取一塊內(nèi)存空間,注意這里只會開辟空間,不會自動調(diào)用構(gòu)造函數(shù)對這塊空間進(jìn)行初始化。
  • 然后調(diào)用allocator_traits::construct函數(shù)對這塊空間進(jìn)行初始化,調(diào)用該函數(shù)時(shí)會傳入這塊空間的地址和用戶傳入的參數(shù)(需要經(jīng)過完美轉(zhuǎn)發(fā))。
  • 在allocator_traits::construct函數(shù)中會使用定位new表達(dá)式,顯示調(diào)用構(gòu)造函數(shù)對這塊空間進(jìn)行初始化,調(diào)用構(gòu)造函數(shù)時(shí)會傳入用戶傳入的參數(shù)(需要經(jīng)過完美轉(zhuǎn)發(fā))。
  • 將初始化好的新結(jié)點(diǎn)插入到對應(yīng)的數(shù)據(jù)結(jié)構(gòu)當(dāng)中,比如list容器就是將新結(jié)點(diǎn)插入到底層的雙鏈表中。

emplace系列接口的意義

由于emplace系列接口的可變模板參數(shù)的類型都是萬能引用,因此既可以接收左值對象,也可以接收右值對象,還可以接收參數(shù)包。

  • 如果調(diào)用emplace系列接口時(shí)傳入的是左值對象,那么首先需要先在此之前調(diào)用構(gòu)造函數(shù)實(shí)例化出一個(gè)左值對象,最終在使用定位new表達(dá)式調(diào)用構(gòu)造函數(shù)對空間進(jìn)行初始化時(shí),會匹配到拷貝構(gòu)造函數(shù)。
  • 如果調(diào)用emplace系列接口時(shí)傳入的是右值對象,那么就需要在此之前調(diào)用構(gòu)造函數(shù)實(shí)例化出一個(gè)右值對象,最終在使用定位new表達(dá)式調(diào)用構(gòu)造函數(shù)對空間進(jìn)行初始化時(shí),就會匹配到移動構(gòu)造函數(shù)。
  • 如果調(diào)用emplace系列接口時(shí)傳入的是參數(shù)包,那就可以直接調(diào)用函數(shù)進(jìn)行插入,并且最終在使用定位new表達(dá)式調(diào)用構(gòu)造函數(shù)對空間進(jìn)行初始化時(shí),匹配到的是構(gòu)造函數(shù)。

總結(jié)一下:

  • 傳入左值對象,需要調(diào)用構(gòu)造函數(shù)+拷貝構(gòu)造函數(shù)。
  • 傳入右值對象,需要調(diào)用構(gòu)造函數(shù)+移動構(gòu)造函數(shù)。
  • 傳入?yún)?shù)包,只需要調(diào)用構(gòu)造函數(shù)。

當(dāng)然,這里的前提是容器中存儲的元素所對應(yīng)的類,是一個(gè)需要深拷貝的類,并且該類實(shí)現(xiàn)了移動構(gòu)造函數(shù)。否則在調(diào)用emplace系列接口時(shí),傳入左值對象和傳入右值對象的效果都是一樣的,都需要調(diào)用一次構(gòu)造函數(shù)和一次拷貝構(gòu)造函數(shù)。

實(shí)際emplace系列接口的一部分功能和原有各個(gè)容器插入接口是重疊的,因?yàn)槿萜髟械膒ush_back、push_front和insert函數(shù)也提供了右值引用版本的接口,如果調(diào)用這些接口時(shí)如果傳入的是右值對象,那么最終也是會調(diào)用對應(yīng)的移動構(gòu)造函數(shù)進(jìn)行資源的移動的。

emplace接口的意義:

emplace系列接口最大的特點(diǎn)就是支持傳入?yún)?shù)包,用這些參數(shù)包直接構(gòu)造出對象,這樣就能減少一次拷貝,這就是為什么有人說emplace系列接口更高效的原因。
但emplace系列接口并不是在所有場景下都比原有的插入接口高效,如果傳入的是左值對象或右值對象,那么emplace系列接口的效率其實(shí)和原有的插入接口的效率是一樣的。
emplace系列接口真正高效的情況是傳入?yún)?shù)包的時(shí)候,直接通過參數(shù)包構(gòu)造出對象,避免了中途的一次拷貝。
 

通過下面的場景我們來驗(yàn)證一下:

namespace nxbw
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			cout << "string(char* str)" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		// s1.swap(s2)
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}
		// 拷貝構(gòu)造
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 深拷貝" << endl;
			string tmp(s._str);
			swap(tmp);
		}
		// 賦值重載
		string& operator=(const string& s)
		{

			cout << "string& operator=(string s) -- 深拷貝" << endl;
			string tmp(s);
			swap(tmp);
			return *this;
		}
		// 移動構(gòu)造
		string(string&& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			cout << "string(string&& s) -- 移動語義" << endl;
			swap(s);
		}
		// 移動賦值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移動語義" << endl;
			swap(s);
			return *this;
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}
		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}

			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}
		//string operator+=(char ch)
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}
		const char* c_str() const
		{
			return _str;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做標(biāo)識的\0
	};
}
int main()
{
	list<pair<nxbw::string, int>> mylist;
	pair<nxbw::string, int> kv("nxbw", 10); //構(gòu)造
	mylist.emplace_back(kv); //傳左值,
	mylist.emplace_back(pair<nxbw::string, int>("nxbw", 10)); //傳右值
	mylist.emplace_back("nxbw", 10); //傳參數(shù)包

	return 0;
}

由于我們在string的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)和移動構(gòu)造函數(shù)當(dāng)中均打印了一條提示語句,因此我們可以通過控制臺輸出來判斷這些函數(shù)是否被調(diào)用。

下面我們用一個(gè)容器來存儲模擬實(shí)現(xiàn)的string,并以不同的傳參形式調(diào)用emplace系列函數(shù)。比如:

說明一下:

模擬實(shí)現(xiàn)string的拷貝構(gòu)造函數(shù)時(shí)復(fù)用了構(gòu)造函數(shù),因此在調(diào)用string拷貝構(gòu)造的后面會緊跟著調(diào)用一次構(gòu)造函數(shù)。
為了更好的體現(xiàn)出參數(shù)包的概念,因此這里list容器中存儲的元素類型是pair,我們是通過觀察string對象的處理過程來判斷pair的處理過程的。
這里也可以以不同的傳參方式調(diào)用push_back函數(shù),順便驗(yàn)證一下容器原有的插入函數(shù)的執(zhí)行邏輯。比如:

int main()
{
	list<pair<nxbw::string, int>> mylist;
	pair<nxbw::string, int> kv("nxbw", 10);

	mylist.push_back(kv); //傳左值
	mylist.push_back(pair<nxbw::string, int>("nxbw", 10)); //傳右值
	mylist.push_back({ "nxbw", 10 }); //使用列表初始化

	return 0;
}

模擬實(shí)現(xiàn):emplace接口

namespace nxbw
{
	// 模擬實(shí)現(xiàn)list在之前的章節(jié)有提過,這里只是將原來的代碼多增加一些接口的片段代碼

	// 這是list需要用到的節(jié)點(diǎn)類
	template<class T>
	struct __list_node
	{
		__list_node(const T& val = T())
			:_data(val), _prev(nullptr), _next(nullptr)
		{}
		// 這里需要在原來的基礎(chǔ)上需要增加一個(gè)可變模板參數(shù)模板的構(gòu)造函數(shù),方便下面使用new
		template<class ...Args>
		__list_node(Args&& ...args)
			: _data(std::forward<Args>(args)...), _prev(nullptr), _next(nullptr)
		{}


		T _data;
		__list_node* _prev;
		__list_node* _next;
	};


	template<class T>
	struct list
	{
		template<class ...Args>
		iterator emplace(iterator position, Args&&... args)
		{

			node* cur = position._node;
			node* prev = cur->_prev;
			// 函數(shù)參數(shù)包的完美轉(zhuǎn)發(fā)
			node* newnode = new node(forward<Args>(args)...);

			prev->_next = newnode;
			newnode->_prev = prev;

			newnode->_next = cur;
			cur->_prev = newnode;

			return iterator(cur);
		}

		template<class ...Args>
		void emplace_back(Args&&... args)
		{
			// 函數(shù)參數(shù)包的完美轉(zhuǎn)發(fā)
			emplace(end(), forward<Args>(args)...);
		}

        // 獲取節(jié)點(diǎn)函數(shù),這里更新成了萬能引用版的
		template<class T>
		node* get_node(T&& val = T())
		{
			node* new_node = new node(forward<T>(val)); // 完美轉(zhuǎn)發(fā)
			new_node->_prev = new_node;
			new_node->_next = new_node;
			return new_node;
		}

	private:
		__list_node<T>* _head; // 指向節(jié)點(diǎn)類的指針
	};
};

emplace系列和push_back以及insert的區(qū)別

效率方面:對于左值引用版本的push_back和insert來說確實(shí)有很大的效率提升,對于右值引用版本的push_back和insert來說效率其實(shí)差不多,因?yàn)橐苿淤x值/拷貝代價(jià)足夠小

構(gòu)造復(fù)雜對象:當(dāng)元素的構(gòu)造比叫復(fù)雜時(shí),emplace可以讓代碼更簡潔,直接傳入構(gòu)造參數(shù)即可

到此這篇關(guān)于C++11中可變模板參數(shù)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++11 可變模板參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++模擬實(shí)現(xiàn)vector流程詳解

    C++模擬實(shí)現(xiàn)vector流程詳解

    這篇文章主要介紹了C++容器Vector的模擬實(shí)現(xiàn),Vector是一個(gè)能夠存放任意類型的動態(tài)數(shù)組,有點(diǎn)類似數(shù)組,是一個(gè)連續(xù)地址空間,下文更多詳細(xì)內(nèi)容的介紹,需要的小伙伴可以參考一下
    2022-08-08
  • 深入講解C++中的構(gòu)造函數(shù)

    深入講解C++中的構(gòu)造函數(shù)

    這篇文章主要介紹了C++中的構(gòu)造函數(shù),是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • 教你如何使用qt quick-PathView實(shí)現(xiàn)好看的home界面

    教你如何使用qt quick-PathView實(shí)現(xiàn)好看的home界面

    pathView的使用類似與ListView,都需要模型(model)和代理(delegate),只不過pathView多了一個(gè)路徑(path)屬性,顧名思義路徑就是item滑動的路徑,下面給大家分享qt quick-PathView實(shí)現(xiàn)好看的home界面,一起看看吧
    2021-06-06
  • c++自帶的查找函數(shù)詳解

    c++自帶的查找函數(shù)詳解

    這篇文章主要介紹了c++自帶的查找函數(shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • 淺析C/C++ 中return *this和return this的區(qū)別

    淺析C/C++ 中return *this和return this的區(qū)別

    return *this返回的是當(dāng)前對象的克隆或者本身,return this返回當(dāng)前對象的地址,下面通過本文給大家介紹C/C++ 中return *this和return this的區(qū)別,感興趣的朋友一起看看吧
    2019-10-10
  • VS2022配置編譯使用boost庫的實(shí)現(xiàn)

    VS2022配置編譯使用boost庫的實(shí)現(xiàn)

    本文介紹了如何在VS2022中配置和編譯使用Boost庫的步驟,包括下載Boost、解壓、配置環(huán)境變量和編譯等過程,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-12-12
  • c語言的注釋定界符詳解

    c語言的注釋定界符詳解

    在本文里小編給大家分享的是關(guān)于c語言的注釋定界符知識點(diǎn)詳解,需要的朋友們可以跟著學(xué)習(xí)下。
    2020-02-02
  • C語言數(shù)據(jù)結(jié)構(gòu)與算法之排序總結(jié)(二)

    C語言數(shù)據(jù)結(jié)構(gòu)與算法之排序總結(jié)(二)

    這篇文章住要介紹的是選擇類排序中的簡單、樹形和堆排序,歸并排序、分配類排序的基數(shù)排序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2021-12-12
  • 淺談MFC 改變控件大小和位置

    淺談MFC 改變控件大小和位置

    在用VC開發(fā)應(yīng)用程序時(shí),經(jīng)常會要做一些可以改變大小的對話框,而這個(gè)時(shí)候就要求對話框上的控件會隨著對話框大小的改變而改變自己的位置和大小。下面我們就來探討下在MFC中如何改變控件大小和位置
    2015-06-06
  • C++歸并算法實(shí)例

    C++歸并算法實(shí)例

    這篇文章主要介紹了C++歸并算法,實(shí)例分析了C++實(shí)現(xiàn)基于歸并算法合并線性表的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07

最新評論