1. 程式人生 > 實用技巧 >【C/C++】【C++11】auto詳解

【C/C++】【C++11】auto詳解

auto型別常規推斷

C++11中,auto用於自動型別推斷,在宣告變數的時候根據變數初始值的型別自動為此變數選擇匹配的型別,不需要程式設計師顯示指定型別;

  • auto自動型別推斷髮生在編譯器期間,所以不會影響程式執行期間的效能;

  • auto定義變數必須立即初始化;這樣編譯器才能推斷它的實際型別;編譯的時候才能確定auto的型別和整個變數的型別;編譯期間可以用真正 的型別來替換auto

  • auto的使用靈活,可以和指標,引用,const等限定符結合使用;

  • auto推匯出來以後代表一個具體型別;auto實際也是一個型別;

  • auto型別推斷和上邊這個函式模板推斷非常類似;

  • auto這個東西也是型別宣告的一部分;[理解成型別佔位符]

傳值方式

  • 傳值方式的auto會拋棄引用,const等限定符;
auto x = 27;
const auto& xy = x; //xy = const int &
auto xy2 = xy; //xy2 = int,auto = int; 傳值方式:引用型別會被拋棄,const屬性會被拋棄,對方看成新副本;

using boost::typeindex::type_id_with_cvr;
cout << type_id_with_cvr<decltype(xy2)>().pretty_name() << endl;
#include <iostream>
#include <boost/type_index.hpp>

using namespace std;

//const auto &xy = x;
template <typename T> //T是型別模板引數,T是由型別的
void func(const T& tmp)//tmp形參,形參是有型別的 tmp形參的型別和T模板引數的型別不一樣
{
	//T的型別不僅僅和呼叫者提供的實參有關係,還和tmp的型別有關;

	cout << "--------------s-----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //顯示T型別
	cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //顯示tmp型別
	cout << "---------------e----------------" << endl;
}

int main()
{  
	//auto型別推斷和函式模板型別推斷非常相似
	auto x = 27;
	const auto& xy = x; //xy = const int & 
	func(x); //T = int , tmp = const int & 



	using boost::typeindex::type_id_with_cvr;
	cout << type_id_with_cvr<decltype(xy)>().pretty_name() << endl; //xy
	return 0; 
}

指標或引用但不是萬能引用

指標或引用型別但不是萬能引用,不會拋棄const等限定符,但是會丟棄引用;


#include <iostream>
#include <boost/type_index.hpp>


using namespace std;

//const auto &xy = x;
template <typename T> //T是型別模板引數,T是由型別的
void func(const T& tmp)//tmp形參,形參是有型別的 tmp形參的型別和T模板引數的型別不一樣
{
	//T的型別不僅僅和呼叫者提供的實參有關係,還和tmp的型別有關;

	cout << "--------------s-----------------" << endl;
	using boost::typeindex::type_id_with_cvr;
	cout << "T = " << type_id_with_cvr<T>().pretty_name() << endl; //顯示T型別
	cout << "tmp = " << type_id_with_cvr<decltype(tmp)>().pretty_name() << endl; //顯示tmp型別
	cout << "---------------e----------------" << endl;
}

int main()
{  
	//auto型別推斷和函式模板型別推斷非常相似
	auto x = 27;
	const auto& xy = x; //xy = const int &

	auto xy2 = xy; //傳值方式:引用型別和const型別都會被丟棄
	auto& xy3 = xy; //xy3 = const int &, auto = const int引用會被丟棄,cosnt屬性保留

	auto y = new auto(100); // y = int*, auto = int*; auto可以用new操作符
	const auto* x_p = &x; //xp = const int *, auto  = int;


	auto* xp2 = &x; //xp2 = int *, auto = int;
	auto xp3 = &x; //xp3 = int *, auto = int *; xp3沒有宣告為指標,但auto把它推導成了指標型別


	//指標或引用型別但不是萬能引用,不會拋棄const等限定符,但是會丟棄引用;
	using boost::typeindex::type_id_with_cvr;
	cout << type_id_with_cvr<decltype(xp3)>().pretty_name() << endl; //xy
	return 0; 
}



萬能引用型別


#include <iostream>
#include <boost/type_index.hpp>


using namespace std;

nt main()
{  
	//auto型別推斷和函式模板型別推斷非常相似

	//萬能引用
	auto x = 27;
	const int x2 = x;
	auto&& yy = x; //x是左值,auto = int&, yy = int &, 出現了引用摺疊,系統幫助我們處理掉了
	auto&& a_x2 = x2; //x2是左值,auto = int &, a_x2 = const int &
	auto&& a_x3 = 100; //100是右值,auto = int, a_x3 = int &&



	using boost::typeindex::type_id_with_cvr;
	cout << type_id_with_cvr<decltype(a_x2)>().pretty_name() << endl; //xy
	return 0; 
}

auto型別針對陣列和函式的推斷


#include <iostream>
#include <boost/type_index.hpp>


using namespace std;


void func(double x, int y) 
{
	cout << x << " " << y << endl;
};



int main()
{  
	const char str[] = "Hello world";
	auto arr = str; //const char *

	auto& my_arr2 = str; //const char (&)[12]

	int a[2] = { 1, 2 };
	auto a_au = a; //auto  = int *, a_au = int *

	auto tmp_f = func; // tmp_f = void(*) (double, int) 函式指標

	auto& tmp_f_ref = func; // tmp_f = void(&) (double, int) 函式引用


	tmp_f(1, 2);

	using boost::typeindex::type_id_with_cvr;
	cout << type_id_with_cvr<decltype(tmp_f_ref)>().pretty_name() << endl; //xy
	return 0; 
}



auto型別std::initializer_list的特殊推斷


#include <iostream>
#include <boost/type_index.hpp>


using namespace std;


int main()
{  
	int x1 = 10; // c++98
	int x2(20); // c++98

	int x3 = { 30 }; // c++11
	int x4{ 10 }; // c++11


	auto y1 = 10; // y1 = int
	auto y2(20); // y2 = int

	auto y3 = { 30 }; // y3 = class std::initializer_list<int>
	auto y4{ 10 }; // y4 = int

	//auto 遇到 = {} 推導規則就不一樣了,特殊情況 class std::initializer_list<int> C++11引入的新型別(類模板),表示某種特定的值的陣列
    //class std::initializer_list<int>推導只有auto能推匯出來,這一點是auto型別推導和模板型別推導的區別之處,其他和模板型別推導都差
	using boost::typeindex::type_id_with_cvr;
	cout << type_id_with_cvr<decltype(y4)>().pretty_name() << endl; //xy
	return 0; 
}



auto不使用場合舉例

不能用於函式引數

普通成員變數


#include <iostream>
#include <boost/type_index.hpp>
using namespace std;

class Test
{
public:
	//auto m_i = 12; //普通成員變數不能是auto
	static const auto m_c_s = 15; //static const靜態成員可以使用auto,使用auto後,其值必須在類內初始化
							      //static const和普通靜態成員不一樣,普通靜態成員在這裡宣告,在cpp中定義和初始化
								  //static cosnt靜態成員就在這裡定義和初始化
};

int main()
{  

	return 0; 
}

auto使用場合舉例

簡化迭代器寫法


#include <iostream>
#include <string>
#include <map>

using namespace std;


int main()
{  

	std::map<string, int> hashmap;
	for (int i = 0; i < 10; i++)
	{
		hashmap.insert({ to_string(i), i });
	}

	/*std::map<string, int>::iterator iter;
	for (iter = hashmap.begin(); iter != hashmap.end(); ++iter)
		cout << iter->first << " " << iter->second << endl;*/



	for (auto iter = hashmap.begin(); iter != hashmap.end(); ++iter)
		cout << iter->first << " " << iter->second << endl;

	return 0; 
}



無法確定型別


#include <iostream>
#include <string>
#include <map>

using namespace std;



class A
{
public:
	static int test_a()
	{
		return 0;
	}
};


class B
{
public:
	static double test_a()
	{
		return 10.5f;
	}
};

template<typename T>
auto func()
{
	auto value = T::test_a();
	return value;
}

int main()
{  
	cout << func<A>() << endl;
	cout << func<B>() << endl;
	return 0; 
}

總結

auto關鍵字可以看成一個強大的工具;不能濫用,善用