c++11之函數參數包展開


1.關於

本文略帶總結性,參考:泛化之美--C++11可變模版參數的妙用
參數包展開方式有兩種: 遞歸展開 和 逗號表達式展開。
本文代碼並非全部來自參考文章,自己做了注釋和修改。請以原文為准

2. 查詢參數包的參數個數

用下面的函數可以實現查詢參數包的個數

template<typename... Args>
unsigned int length(Args... args)
{
    return sizeof...(args);
}

調用

length(1, "hello", "c++", "11"); // 返回4,4個參數

3.遞歸展開

3.1 注意, 遞歸展開需要考慮爆棧的情況。 說到這里,ubuntu(linux) 默認棧大小8M(使用命令 ulimit -a查看), Win下,Visual Studio 默認棧大小1M(連接器->系統)。
3.2 需要兩個函數:遞歸終止函數遞歸函數
3.3 一個例子,輸出各個元素。函數參數為參數包的形式,使用遞歸展開.

// 1.遞歸終止函數
void print()
{
	;
}

// 2.遞歸執行函數
template<typename T, typename... Args>
void print(T head, Args... args)
{
	std::cout << head << (sizeof...(args) > 0 ? ", " : "");
	print(args...);
}

3.4 調用及執行結果

print(1, "hello", "C++", 11);

3.5 其執行過程

print(1, "hello", "C++", 11);
print("hello", "C++", 11);
print("C++", 11);
print(11);
print();

例子中,遞歸終止到第0參數截止。根據執行過程可知,終止函數可以改為1個參數,最后一個函數僅僅作為終止遞歸使用,終止遞歸改為1個參數的函數還可以提高性能(減少函數的調用)。

3.6 遞歸終止改為一個參數

// 1.遞歸終止函數
template<typename T>
void print(const T& t)
{
	std::cout << t << endl;
}

// 2.遞歸執行函數
template<typename T, typename... Args>
void print(T head, Args... args)
{
	std::cout << head << (sizeof...(args) > 0 ? ", " : "");
	print(args...);
}

同樣的,執行上面的調用代碼print(1, "hello", "C++", 11);,其執行過程如下

print(1, "hello", "C++", 11);
print("hello", "C++", 11);
print("C++", 11);
print(11);

3.7 再看一個遞歸求和的例子, 同樣是使用參數包的形式

// 1.遞歸終止函數
template <typename T>
T sum(const T& t)
{
	return t;
}

// 2.遞歸函數
template <typename T, typename ... Args>
T sum(const T& head, const Args... args)
{
	return head + sum<T>(args...);
}

4.逗號表達式展開

  逗號表達式?了解一下

4.1 回到上面print的例子,改為逗號表達式

// 1.用作輸出每個參數
template<typename T>
void show_arg(const T& t)
{
	std::cout << t <<std::endl;
}

// 2.用作展開參數包
template <typename ... Args>
void expand(const Args&... args)
{
	int arr[] = {(show_arg(args), 0)...}; /// (1)
}

代碼中,(1)的逗號表達式為: (show_arg(args), 0)。先執行表達式1(show_arg(args)),再執行表達式2(0)。 使用調用代碼expand(1, 2, 3, 4),(1)處的逗號表達式展開結果如下

int arr[] = { (show_arg(1), 0) , (show_arg(2), 0), (show_arg(3), 0), (show_arg(4), 0) };

而,第一個逗號表達式結果為0, 第二逗號表達式的結果為0, .... 最后一個逗號表達式展開后,逗號表達式的結果為0,所以(1)的代碼最后是這樣的:

int arr[] = {0, 0, 0, 0}; /// (2)

(2)的代碼聲明了一個int數組,數組有4個元素。 展開參數包的方式相當巧妙,比起遞歸,更加方便了。

4.2 使用lambda + 逗號表達式展開參數包
還是同樣的例子,輸出參數包元素。


template<typename Func, typename...Args>
void show_args(const Func &f, Args&... args)
{
	// 初始化列表,列表的類型為int, std::initializer_list是c++11引入的模板
	std::initializer_list<int>{(f(std::forward< Args>(args)), 0)...};
}

// 調用 
show_args([](const int & item) {std:: cout << item << ", ";  }, 1, 2, 3, 4); /// 輸出: 1, 2, 3, 4,


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM