在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ A.6 變參模板
3.4 本章總結(jié)
6.3 基于鎖設(shè)計更加復雜的數(shù)據(jù)結(jié)構(gòu)
6.1 為并發(fā)設(shè)計的意義何在?
5.2 <code>C++</code>中的原子操作和原子類型
A.7 自動推導變量類型
2.1 線程管理的基礎(chǔ)
8.5 在實踐中設(shè)計并發(fā)代碼
2.4 運行時決定線程數(shù)量
2.2 向線程函數(shù)傳遞參數(shù)
第4章 同步并發(fā)操作
2.3 轉(zhuǎn)移線程所有權(quán)
8.3 為多線程性能設(shè)計數(shù)據(jù)結(jié)構(gòu)
6.4 本章總結(jié)
7.3 對于設(shè)計無鎖數(shù)據(jù)結(jié)構(gòu)的指導建議
關(guān)于這本書
A.1 右值引用
2.6 本章總結(jié)
D.2 &lt;condition_variable&gt;頭文件
A.6 變參模板
6.2 基于鎖的并發(fā)數(shù)據(jù)結(jié)構(gòu)
4.5 本章總結(jié)
A.9 本章總結(jié)
前言
第10章 多線程程序的測試和調(diào)試
5.4 本章總結(jié)
第9章 高級線程管理
5.1 內(nèi)存模型基礎(chǔ)
2.5 識別線程
第1章 你好,C++的并發(fā)世界!
1.2 為什么使用并發(fā)?
A.5 Lambda函數(shù)
第2章 線程管理
4.3 限定等待時間
D.3 &lt;atomic&gt;頭文件
10.2 定位并發(fā)錯誤的技術(shù)
附錄B 并發(fā)庫的簡單比較
5.3 同步操作和強制排序
A.8 線程本地變量
第8章 并發(fā)代碼設(shè)計
3.3 保護共享數(shù)據(jù)的替代設(shè)施
附錄D C++線程庫參考
第7章 無鎖并發(fā)數(shù)據(jù)結(jié)構(gòu)設(shè)計
D.7 &lt;thread&gt;頭文件
D.1 &lt;chrono&gt;頭文件
4.1 等待一個事件或其他條件
A.3 默認函數(shù)
附錄A 對<code>C++</code>11語言特性的簡要介紹
第6章 基于鎖的并發(fā)數(shù)據(jù)結(jié)構(gòu)設(shè)計
封面圖片介紹
7.2 無鎖數(shù)據(jù)結(jié)構(gòu)的例子
8.6 本章總結(jié)
8.1 線程間劃分工作的技術(shù)
4.2 使用期望等待一次性事件
8.4 設(shè)計并發(fā)代碼的注意事項
D.5 &lt;mutex&gt;頭文件
3.1 共享數(shù)據(jù)帶來的問題
資源
9.3 本章總結(jié)
10.3 本章總結(jié)
10.1 與并發(fā)相關(guān)的錯誤類型
D.4 &lt;future&gt;頭文件
3.2 使用互斥量保護共享數(shù)據(jù)
9.1 線程池
1.1 何謂并發(fā)
9.2 中斷線程
4.4 使用同步操作簡化代碼
A.2 刪除函數(shù)
1.3 C++中的并發(fā)和多線程
1.4 開始入門
第5章 C++內(nèi)存模型和原子類型操作
消息傳遞框架與完整的ATM示例
8.2 影響并發(fā)代碼性能的因素
7.1 定義和意義
D.6 &lt;ratio&gt;頭文件
A.4 常量表達式函數(shù)
7.4 本章總結(jié)
1.5 本章總結(jié)
第3章 線程間共享數(shù)據(jù)

A.6 變參模板

變參模板:就是可以使用不定數(shù)量的參數(shù)進行特化的模板。就像你接觸到的變參函數(shù)一樣,printf就接受可變參數(shù)?,F(xiàn)在,就可以給你的模板指定不定數(shù)量的參數(shù)了。變參模板在整個C++線程庫中都有使用,例如:std::thread的構(gòu)造函數(shù)就是一個變參類模板。從使用者的角度看,僅知道模板可以接受無限個參數(shù)就夠了,不過當要寫這么一個模板或?qū)ζ涔ぷ髟砗芨信d趣時,就需要了解一些細節(jié)。

和變參函數(shù)一樣,變參部分可以在參數(shù)列表章使用省略號...代表,變參模板需要在參數(shù)列表中使用省略號:

template<typename ... ParameterPack>
class my_template
{};

即使主模板不是變參模板,模板進行部分特化的類中,也可以使用可變參數(shù)模板。例如,std::packaged_task<>(見4.2.1節(jié))的主模板就是一個簡單的模板,這個簡單的模板只有一個參數(shù):

template<typename FunctionType>
class packaged_task;

不過,并不是所有地方都這樣定義;對于部分特化模板來說,其就像是一個“占位符”:

template<typename ReturnType,typename ... Args>
class packaged_task<ReturnType(Args...)>;

部分特化的類就包含實際定義的類;在第4章,可以寫一個std::packaged_task<int(std::string,double)>來聲明一個以std::string和double作為參數(shù)的任務(wù),當執(zhí)行這個任務(wù)后結(jié)果會由std::future<int>進行保存。

聲明展示了兩個變參模板的附加特性。第一個比較簡單:普通模板參數(shù)(例如ReturnType)和可變模板參數(shù)(Args)可以同時聲明。第二個特性,展示了Args...特化類的模板參數(shù)列表中如何使用,為了展示實例化模板中的Args的組成類型。實際上,因為這是部分特化,所以其作為一種模式進行匹配;在列表中出現(xiàn)的類型(被Args捕獲)都會進行實例化。參數(shù)包(parameter pack)調(diào)用可變參數(shù)Args,并且使用Args...作為包的擴展。

和可變參函數(shù)一樣,變參部分可能什么都沒有,也可能有很多類型項。例如,std::packaged_task<my_class()>中ReturnType參數(shù)就是my_class,并且Args參數(shù)包是空的,不過std::packaged_task<void(int,double,my_class&,std::string*)>中,ReturnType為void,并且Args列表中的類型就有:int, double, my_class&和std::string*。

A.6.1 擴展參數(shù)包

變參模板主要依靠包括擴展功能,因為不能限制有更多的類型添加到模板參數(shù)中。首先,列表中的參數(shù)類型使用到的時候,可以使用包擴展,比如:需要給其他模板提供類型參數(shù)。

template<typename ... Params>
struct dummy
{
  std::tuple<Params...> data;
};

成員變量data是一個std::tuple<>實例,包含所有指定類型,所以dummy<int, double, char>的成員變量就為std::tuple<int, double, char>。

可以將包擴展和普通類型相結(jié)合:

template<typename ... Params>
struct dummy2
{
  std::tuple<std::string,Params...> data;
};

這次,元組中添加了額外的(第一個)成員類型std::string。其優(yōu)雅指出在于,可以通過包擴展的方式創(chuàng)建一種模式,這種模式會在之后將每個元素拷貝到擴展之中,可以使用...來表示擴展模式的結(jié)束。

例如,創(chuàng)建使用參數(shù)包來創(chuàng)建元組中所有的元素,不如在元組中創(chuàng)建指針,或使用std::unique_ptr<>指針,指向?qū)?yīng)元素:

template<typename ... Params>
struct dummy3
{
  std::tuple<Params* ...> pointers;
  std::tuple<std::unique_ptr<Params> ...> unique_pointers;
};

類型表達式會比較復雜,提供的參數(shù)包是在類型表達式中產(chǎn)生,并且表達式中使用...作為擴展。當參數(shù)包已經(jīng)擴展 ,包中的每一項都會代替對應(yīng)的類型表達式,在結(jié)果列表中產(chǎn)生相應(yīng)的數(shù)據(jù)項。因此,當參數(shù)包Params包含int,int,char類型,那么std::tuple<std::pair<std::unique_ptr<Params>,double> ... >將擴展為std::tuple<std::pair<std::unique_ptr<int>,double>,std::pair<std::unique_ptr<int>,double>,std::pair<std::unique_ptr<char>, double> >。如果包擴展被當做模板參數(shù)列表使用,那么模板就不需要變長的參數(shù)了;如果不需要了,參數(shù)包就要對模板參數(shù)的要求進行準確的匹配:

template<typename ... Types>
struct dummy4
{
  std::pair<Types...> data;
};
dummy4<int,char> a;  // 1 ok,為std::pair<int, char>
dummy4<int> b;  // 2 錯誤,無第二個類型
dummy4<int,int,int> c;  // 3 錯誤,類型太多

可以使用包擴展的方式,對函數(shù)的參數(shù)進行聲明:

template<typename ... Args>
void foo(Args ... args);

這將會創(chuàng)建一個新參數(shù)包args,其是一組函數(shù)參數(shù),而非一組類型,并且這里...也能像之前一樣進行擴展。例如,可以在std::thread的構(gòu)造函數(shù)中使用,使用右值引用的方式獲取函數(shù)所有的參數(shù)(見A.1節(jié)):

template<typename CallableType,typename ... Args>
thread::thread(CallableType&& func,Args&& ... args);

函數(shù)參數(shù)包也可以用來調(diào)用其他函數(shù),將制定包擴展成參數(shù)列表,匹配調(diào)用的函數(shù)。如同類型擴展一樣,也可以使用某種模式對參數(shù)列表進行擴展。

例如,使用std::forward()以右值引用的方式來保存提供給函數(shù)的參數(shù):

template<typename ... ArgTypes>
void bar(ArgTypes&& ... args)
{
  foo(std::forward<ArgTypes>(args)...);
}

注意一下這個例子,包擴展包括對類型包ArgTypes和函數(shù)參數(shù)包args的擴展,并且省略了其余的表達式。

當這樣調(diào)用bar函數(shù):

int i;
bar(i,3.141,std::string("hello "));

將會擴展為

template<>
void bar<int&,double,std::string>(
         int& args_1,
         double&& args_2,
         std::string&& args_3)
{
  foo(std::forward<int&>(args_1),
      std::forward<double>(args_2),
      std::forward<std::string>(args_3));
}

這樣就將第一個參數(shù)以左值引用的形式,正確的傳遞給了foo函數(shù),其他兩個函數(shù)都是以右值引用的方式傳入的。

最后一件事,參數(shù)包中使用sizeof...操作可以獲取類型參數(shù)類型的大小,sizeof...(p)就是p參數(shù)包中所包含元素的個數(shù)。不管是類型參數(shù)包或函數(shù)參數(shù)包,結(jié)果都是一樣的。這可能是唯一一次在使用參數(shù)包的時候,沒有加省略號;這里的省略號是作為sizeof...操作的一部分,所以不算是用到省略號。

下面的函數(shù)會返回參數(shù)的數(shù)量:

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

就像普通的sizeof操作一樣,sizeof...的結(jié)果為常量表達式,所以其可以用來指定定義數(shù)組長度,等等。