C++11泛型-函數(shù)模板

一执泰、為什么要有函數(shù)模板

在泛型編程出現(xiàn)前典蝌,我們要實(shí)現(xiàn)一個(gè)swap函數(shù)得這樣寫(xiě):

void swap(int &a, int &b) {
    int tmp{a};
    a = b;
    b = tmp;
}

但這個(gè)函數(shù)只支持int型的變量交換距潘,如果我們要做float, long, double, std::string等等類型的交換時(shí)罗侯,只能不斷加入新的重載函數(shù)。這樣做不但代碼冗余伏钠,容易出錯(cuò),還不易維護(hù)谨设。C++函數(shù)模板有效解決了這個(gè)問(wèn)題熟掂。函數(shù)模板擺脫了類型的限制,提供了通用的處理過(guò)程扎拣,極大提升了代碼的重用性赴肚。

二、什么是函數(shù)模板

cppreference中給出的定義是"函數(shù)模板定義一族函數(shù)"鹏秋,怎么理解呢尊蚁?我們先來(lái)看一段簡(jiǎn)單的代碼

#include <iostream>

template<typename T>
void swap(T &a, T &b) {
    T tmp{a};
    a = b;
    b = tmp;
}

int main() {
    int a = 2, b = 3;
    swap(a, b);  // 使用函數(shù)模板
    std::cout << "a=" << a << ", b=" << b << std::endl;
}

swap支持多種類型的通用交換邏輯。它跟普通C++函數(shù)的區(qū)別在于其函數(shù)聲明(declaration)前面加了個(gè)template<typename T>侣夷,這句話告訴編譯器横朋,swap中(函數(shù)參數(shù)、返回值百拓、函數(shù)體中)出現(xiàn)類型T時(shí)琴锭,不要報(bào)錯(cuò),T是一個(gè)通用類型衙传。
函數(shù)模板的格式:

template<parameter-list> function-declaration

函數(shù)模板在形式上分為兩部分:模板决帖、函數(shù)。在函數(shù)前面加上template<...>就成為函數(shù)模板蓖捶,因此對(duì)函數(shù)的各種修飾(inline地回、constexpr等)需要加在function-declaration上,而不是template前。如

template<typename T>
inline T min(const T &, const T &);

parameter-list是由英文逗號(hào)(,)分隔的列表刻像,每項(xiàng)可以是下列之一:

序號(hào) 名稱 說(shuō)明
1 非類型形參 已知的數(shù)據(jù)類型畅买,如整數(shù)、指針等细睡,C++11中有三種形式:
int N
int N = 1: 帶默認(rèn)值谷羞,該值必須是一個(gè)常量或常量表達(dá)式
int ...N: 模板參數(shù)包(可變參數(shù)模板)
2 類型形參 swap值用的形式,格式為:
typename name[ = default]
typename ... name: 模板參數(shù)包
3 模板模板形參 沒(méi)錯(cuò)有兩個(gè)"模板"溜徙,這個(gè)比較復(fù)雜湃缎,有興趣的同學(xué)可以參考
cppreference之模板形參與模板實(shí)參

上面swap函數(shù)模板,使用了類型形參蠢壹。函數(shù)模板就像是一種契約嗓违,任何滿足該契約的類型都可以做為模板實(shí)參。而契約就是函數(shù)實(shí)現(xiàn)中图贸,模板實(shí)參需要支持的各種操作靠瞎。上面swap中T需要滿足的契約為:支持拷貝構(gòu)造和賦值。

template<typename T>
void swap(T &a, T &b) {
    T tmp{a};  // 契約一:T需要支持拷貝構(gòu)造
    a = b;     // 契約二:T需要支持賦值操作
    b = tmp;
}

三求妹、函數(shù)模板不是函數(shù)

剛才我們提到函數(shù)模板用來(lái)定義一族函數(shù)乏盐,而不是一個(gè)函數(shù)。C++是一種強(qiáng)類型的語(yǔ)言制恍,在不知道T的具體類型前父能,無(wú)法確定swap需要占用的棧大小(參數(shù)棧,局部變量)净神,同時(shí)也不知道函數(shù)體中T的各種操作如何實(shí)現(xiàn)何吝,無(wú)法生成具體的函數(shù)。只有當(dāng)用具體類型去替換T時(shí)鹃唯,才會(huì)生成具體函數(shù)爱榕,該過(guò)程叫做函數(shù)模板的實(shí)例化。當(dāng)在main函數(shù)中調(diào)用swap(a,b)時(shí)坡慌,編譯器推斷出此時(shí)Tint黔酥,然后編譯器會(huì)生成int版的swap函數(shù)供調(diào)用。所以相較普通函數(shù)洪橘,函數(shù)模板多了生成具體函數(shù)這一步跪者。如果我們只是編寫(xiě)了函數(shù)模板,但不在任何地方使用它(也不顯式實(shí)例化)熄求,則編譯器不會(huì)為該函數(shù)模板生成任何代碼渣玲。

函數(shù)模板實(shí)例化

函數(shù)模板實(shí)例化分為隱式實(shí)例化和顯式實(shí)例化。

3.1 隱式實(shí)例化

仍以swap為例弟晚,我們?cè)趍ain中調(diào)用swap(a,b)時(shí)忘衍,就發(fā)生了隱式實(shí)例化逾苫。當(dāng)函數(shù)模板被調(diào)用,且在之前沒(méi)有顯式實(shí)例化時(shí)枚钓,即發(fā)生函數(shù)模板的隱式實(shí)例化隶垮。如果模板實(shí)參能從調(diào)用的語(yǔ)境中推導(dǎo),則不需要提供秘噪。

#include <iostream>

template<typename T>
void print(const T &r) {
    std::cout << r << std::endl;
}
int main() {
    // 隱式實(shí)例化print<int>(int)
    print(1);
    // 實(shí)例化print<char>(char)
    print<>('c');
    // 仍然是隱式實(shí)例化,我們希望編譯器生成print<double>(double)
    print<double>(1);
}

3.2 顯式實(shí)例化

函數(shù)模板定義后勉耀,我們可以通過(guò)顯式實(shí)例化的方式告訴編譯器生成指定實(shí)參的函數(shù)指煎。顯式實(shí)例化聲明會(huì)阻止隱式實(shí)例化。

template<typename R, typename T1, typename T2>
R add(T1 a, T2 b) {
    return static_cast<R>(a + b);
}
// 顯式實(shí)例化
template double add<double, int, double>(int, double);
// 顯式實(shí)例化, 推導(dǎo)出第三個(gè)模板實(shí)參
template int add<int, int>(int, int);
// 全部由編譯器推導(dǎo)
template double add(double, double);

如果我們?cè)陲@式實(shí)例化時(shí)便斥,只指定部分模板實(shí)參至壤,則指定順序必須自左至右依次指定,不能越過(guò)前參模板形參枢纠,直接指定后面的像街。

函數(shù)模板顯式實(shí)例化

四、函數(shù)模板的使用

4.1 使用非類型形參

#include <iostream>

// N必須是編譯時(shí)的常量表達(dá)式
template<typename T, int N>
void printArray(const T (&a)[N]) {
    std::cout << "[";
    const char *sep = "";
    for (int i = 0; i < N; i++, (sep = ", ")) {
        std::cout << sep << a[i];
    }
    std::cout << "]" << std::endl;
}

int main() {
    // T: int, N: 3
    printArray({1, 2, 3});
}
//輸出:[1, 2, 3]

4.2 返回值為auto

有些時(shí)候我們會(huì)碰到這樣一種情況晋渺,函數(shù)的返回值類型取決于函數(shù)參數(shù)某種運(yùn)算后的類型镰绎。對(duì)于這種情況可以采用auto關(guān)鍵字作為返回值占位符。

template<typename T1, typename T2>
auto multi(T a, T b) -> decltype(a * b) {
    return a * b;
}

decltype操作符用于查詢表達(dá)式的數(shù)據(jù)類型木西,也是C++11標(biāo)準(zhǔn)引入的新的運(yùn)算符畴栖,其目的是解決泛型編程中有些類型由模板參數(shù)決定,而難以表示的問(wèn)題八千。為何要將返回值后置呢吗讶?

// 這樣是編譯不過(guò)去的,因?yàn)閐ecltype(a*b)中恋捆,a和b還未聲明照皆,編譯器不知道a和b是什么。
template<typename T1, typename T2>
decltype(a*b) multi(T a, T b) {
    return a*+ b;
}
//編譯時(shí)會(huì)產(chǎn)生如下錯(cuò)誤:error: use of undeclared identifier 'a'

4.3 類成員函數(shù)模板

函數(shù)模板可以做為類的成員函數(shù)沸停。

#include <iostream>

class object {
public:
    template<typename T>
    void print(const char *name, const T &v) {
        std::cout << name << ": " << v << std::endl;
    }
};

int main() {
    object o;
    o.print("name", "Crystal");
    o.print("age", 18);
}

輸出:

name: Crystal
age: 18

需要注意的是:函數(shù)模板不能用作虛函數(shù)膜毁。這是因?yàn)镃++編譯器在解析類的時(shí)候就要確定虛函數(shù)表(vtable)的大小,如果允許一個(gè)虛函數(shù)是函數(shù)模板愤钾,那么就需要在解析這個(gè)類之前掃描所有的代碼爽茴,找出這個(gè)模板成員函數(shù)的調(diào)用或顯式實(shí)例化操作,然后才能確定虛函數(shù)表的大小绰垂,而顯然這是不可行的室奏。

4.4 函數(shù)模板重載

函數(shù)模板之間、普通函數(shù)和模板函數(shù)之間可以重載劲装。編譯器會(huì)根據(jù)調(diào)用時(shí)提供的函數(shù)參數(shù)胧沫,調(diào)用能夠處理這一類型的最佳匹配版本昌简。在匹配度上,一般按照如下順序考慮:

順序 行為
1 最符合函數(shù)名和參數(shù)類型的普通函數(shù)
2 特殊模板(具有非類型形參的模板绒怨,即對(duì)T有類型限制)
3 普通模板(對(duì)T沒(méi)有任何限制的)
4 通過(guò)類型轉(zhuǎn)換進(jìn)行參數(shù)匹配的重載函數(shù)
#include <iostream>

template<typename T>
const T &max(const T &a, const T &b) {
    std::cout << "max(&, &) = ";
    return a > b ? a : b;
}

// 函數(shù)模板重載
template<typename T>
const T *max(T *a, T *b) {
    std::cout << "max(*, *) = ";
    return *a > *b ? a : b;
}

// 函數(shù)模板重載
template<typename T>
const T &max(const T &a, const T &b, const T &c) {
    std::cout << "max(&, &, &) = ";
    const T &t = (a > b ? a : b);
    return t > c ? t : c;
}

// 普通函數(shù)
const char *max(const char *a, const char *b) {
    std::cout << "max(const char *, const char *) = ";
    return strcmp(a, b) > 0 ? a : b;
}

int main() {
    int a = 1, b = 2;
    std::cout << max(a, b) << std::endl;
    std::cout << *max(&a, &b) << std::endl;
    std::cout << max(a, b, 3) << std::endl;
    std::cout << max("en", "ch") << std::endl;
    // 可以通過(guò)空模板實(shí)參列表來(lái)限定編譯器只匹配函數(shù)模板
    std::cout << max<>("en", "ch") << std::endl;
}

輸出

max(&, &) = 2
max(*, *) = 2
max(&, &, &) = 3
max(const char *, const char *) = en
max(*, *) = en

可以通過(guò)空模板實(shí)參列表來(lái)限定編譯器只匹配函數(shù)模板纯赎,比如main函數(shù)中的最后一條語(yǔ)句。

4.5 函數(shù)模板特化

當(dāng)函數(shù)模板需要對(duì)某些類型進(jìn)行特別處理南蹂,這稱為函數(shù)模板的特化犬金。當(dāng)我們定義一個(gè)特化版本時(shí),函數(shù)參數(shù)類型必須與一個(gè)先前聲明的模板中對(duì)應(yīng)的類型匹配六剥。函數(shù)模板特化的本質(zhì)是實(shí)例化一個(gè)模板晚顷,而非重載它。因此疗疟,特化不影響編譯器函數(shù)匹配该默。

template<typename T1, typename T2>
int compare(const T1 &a, const T2 b) {
    return a - b;
}
// 對(duì)const char *進(jìn)行特化
template<>
int compare(const char * const &a, const char * const &b) {
    return strcmp(a, b);
}

上面的例子中針對(duì)const char *的特化,我們其實(shí)可以通過(guò)函數(shù)重載達(dá)到相同效果策彤。因此對(duì)于函數(shù)模板特化栓袖,目前公認(rèn)的觀點(diǎn)是沒(méi)什么用,并且最好別用店诗。Why Not Specialize Function Templates?

但函數(shù)模板特化和重載在重載決議時(shí)有些細(xì)微的差別裹刮。這些差別中比較有用的一個(gè)是阻止某些隱式轉(zhuǎn)換。如當(dāng)你只有void foo(int)時(shí)庞瘸,以浮點(diǎn)類型調(diào)用會(huì)發(fā)生隱式轉(zhuǎn)換必指,這可以通過(guò)特化來(lái)阻止:

template <class T> void foo(T);
template <> void foo(int) {}
foo(3.0); // link error,阻止float隱式轉(zhuǎn)換為int

雖然模板配重載也可以達(dá)到同樣的效果恕洲,但特化版的意圖更加明確塔橡。

函數(shù)模板及其特化版本應(yīng)該聲明在同一個(gè)頭文件中。所有同名模板的聲明應(yīng)該放在前面霜第,然后是這些模板的特化版本葛家。

五、變參函數(shù)模板(模板參數(shù)包)

這是C++11引入的新特性泌类,用來(lái)表示任意數(shù)量的模板形參癞谒。其語(yǔ)法樣式如下:

template<typename ...Args>  // Args: 模板參數(shù)包
void foo(Args ...  args);   // args: 函數(shù)參數(shù)包

在模板形參Args的左邊出現(xiàn)三個(gè)英文點(diǎn)號(hào)"...",表示Args是零個(gè)或多個(gè)類型的列表刃榨,是一個(gè)模板參數(shù)包(template parameter pack)弹砚。正如其名稱一樣,編譯器會(huì)將Args所表示的類型列表打成一個(gè)包枢希,將其當(dāng)做一個(gè)特殊類型處理桌吃。相應(yīng)的函數(shù)參數(shù)列表中也有一個(gè)函數(shù)參數(shù)包。與普通模板函數(shù)一樣苞轿,編譯器從函數(shù)的實(shí)參推斷模板參數(shù)類型茅诱,與此同時(shí)還會(huì)推斷包中參數(shù)的數(shù)量逗物。

// sizeof...() 是C++11引入的參數(shù)包的操作函數(shù),用來(lái)取參數(shù)的數(shù)量
template<typename ...Args>
int length(Args ...  args) {
    return sizeof...(Args);
}

// 以下語(yǔ)句將在屏幕打印出:2
std::cout << length(1, "hello") << std::endl;

變參函數(shù)模板主要用來(lái)處理既不知道要處理的實(shí)參的數(shù)目也不知道它們的類型時(shí)的場(chǎng)景瑟俭。既然我們對(duì)實(shí)參數(shù)量以及類型都一無(wú)所知翎卓,那么我們?cè)趺词褂盟?最常用的方法是遞歸

5.1 遞歸

通過(guò)遞歸來(lái)遍歷所有的實(shí)參摆寄,這需要一點(diǎn)點(diǎn)的技巧失暴,需要給出終止遞歸的條件,否則遞歸將無(wú)限進(jìn)行微饥。

#include <iostream>

// 遞歸終止
void print() {    /// 1
    std::cout << std::endl;
}

// 打印綁定到t的實(shí)參
template<typename T, typename... Args>
void print(const T &t, const Args &... args) {  /// 2
    std::cout << t << (sizeof...(args) > 0 ? ", " : "");
    // 編譯時(shí)展開(kāi):通過(guò)在args右邊添加省略號(hào)(...)進(jìn)行展開(kāi)逗扒,打印參數(shù)包中剩余的參數(shù)
    print(args...);
}

int main() {
    print(1, "hello", "C++", 11);
    return 0;
}
//輸出: 1, hello, C++, 11

該例子的技巧在于,函數(shù)2提供了const T &t參數(shù)畜号,保證至少有一個(gè)參數(shù),避免了與函數(shù)1在args為0時(shí)的沖突允瞧。需要注意的是简软,遞歸是指編譯器遞歸,不是運(yùn)行過(guò)程時(shí)的遞歸調(diào)用述暂。實(shí)際上編譯器為函數(shù)2生成了4個(gè)重載版本痹升,并依次調(diào)用。下圖是在運(yùn)行時(shí)的調(diào)用棧畦韭,可以看到共有5個(gè)重載版本的print函數(shù)疼蛾,4個(gè)遞歸展開(kāi)的函數(shù)2,外加函數(shù)1艺配。遞歸最終結(jié)束在函數(shù)1處察郁。

compiler_recursive.png

5.2 包擴(kuò)展

對(duì)于一個(gè)參數(shù)包,不管是模板參數(shù)包還是函數(shù)參數(shù)包转唉,我們對(duì)它能做的只有兩件事:sizeof...()包擴(kuò)展皮钠。前面我們說(shuō)過(guò)編譯器將參數(shù)包當(dāng)作一個(gè)類型來(lái)處理,因此使用的時(shí)候需要將其展開(kāi)赠法,展開(kāi)時(shí)我們需要提供用于每個(gè)元素的處理模式(pattern)麦轰。包擴(kuò)展就是對(duì)參數(shù)包中的每一個(gè)元素應(yīng)用模式,獲取得擴(kuò)展后的列表砖织。最簡(jiǎn)單的包擴(kuò)展方式就是我們?cè)谏瞎?jié)中看到的const Args &...args...款侵,該擴(kuò)展是將其擴(kuò)展為構(gòu)成元素。C++11還支持更復(fù)雜的擴(kuò)展模式侧纯,如:

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

template<typename T>
std::string to_str(const T &r) {
    std::stringstream ss;
    ss << "\"" << r << "\"";
    return ss.str();
}

template<typename... Args>
void init_vector(std::vector<std::string> &vec, const Args &...args) {
    // 復(fù)雜的包擴(kuò)展方式
    vec.assign({to_str(args)...});
}

int main() {
    std::vector<std::string> vec;
    init_vector(vec, 1, "hello", "world");
    std::cout << "vec.size => " << vec.size() << std::endl;
    for (auto r: vec) {
        std::cout << r << std::endl;
    }
}

運(yùn)行程序?qū)a(chǎn)生如下輸出:

vec.size => 3
"1"
"hello"
"world"

擴(kuò)展過(guò)程中模式(pattern)會(huì)獨(dú)立地應(yīng)用于包中的每一個(gè)元素新锈。同時(shí)pattern也可以接受多個(gè)參數(shù),并非僅僅只能接受參數(shù)包眶熬。

5.3 參數(shù)包的轉(zhuǎn)發(fā)

C++11中壕鹉,我們可以同時(shí)使用變參函數(shù)模板和std::forward機(jī)制來(lái)編寫(xiě)函數(shù)剃幌,將實(shí)參原封不動(dòng)地傳遞給其它函數(shù)。其中典型的應(yīng)用是std::vector::emplace_back操作:

template<typename T, typename Allocator>
template <class... _Args>
void vector<T, Allocator>::emplace_back(_Args&&... __args) {
    push_back (T(forward<_Args>(__args)... ));
}

六晾浴、其它

6.1 函數(shù)模板 .vs. 模板函數(shù)

函數(shù)模板重點(diǎn)在模板负乡。表示這是一個(gè)模板,用來(lái)生成函數(shù)脊凰。
模板函數(shù)重點(diǎn)在函數(shù)抖棘。表示的是由一個(gè)模板生成而來(lái)的函數(shù)。

6.2 cv限定

cv限定是指函數(shù)參數(shù)中有const狸涌、volatile或mutable限定切省。已指定、推導(dǎo)出或從默認(rèn)模板實(shí)參獲得所有模板實(shí)參時(shí)帕胆,函數(shù)參數(shù)列表中每次模板形參的使用都會(huì)被替換成對(duì)應(yīng)的模板實(shí)參朝捆。替換后:

  • 所有數(shù)組類型和函數(shù)類型參數(shù)被調(diào)整成為指針
  • 所有頂層cv限定符從函數(shù)參數(shù)被丟棄,如在普通函數(shù)聲明中懒豹。

頂層cv限定符的去除不影響參數(shù)類型的使用芙盘,因?yàn)樗霈F(xiàn)于函數(shù)中:

template <typename T> void f(T t);
template <typename X> void g(const X x);
template <typename Z> void h(Z z, Z *zp);

// 兩個(gè)不同函數(shù)有同一類型,但在函數(shù)中脸秽, t有不同的cv限定
f<int>(1);       // 函數(shù)類型是 void(int) 儒老, t 為 int
f<const int>(1); // 函數(shù)類型是 void(int) , t 為 const int

// 二個(gè)不同函數(shù)擁有同一類型和同一 x
// (指向此二函數(shù)的指針不相等记餐,且函數(shù)局域的靜態(tài)變量可以擁有不同地址)
g<int>(1);       // 函數(shù)類型是 void(int) 驮樊, x 為 const int
g<const int>(1); // 函數(shù)類型是 void(int) , x 為 const int

// 僅丟棄頂層 cv 限定符:
h<const int>(1, NULL); // 函數(shù)類型是 void(int, const int*) 
                       // z 為 const int 片酝, zp 為 int*
上一篇
C++11多線程-內(nèi)存模型
目錄 下一篇
C++11多線程-類模板
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末囚衔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子雕沿,更是在濱河造成了極大的恐慌佳魔,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晦炊,死亡現(xiàn)場(chǎng)離奇詭異鞠鲜,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)断国,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門贤姆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人稳衬,你說(shuō)我怎么就攤上這事霞捡。” “怎么了薄疚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵碧信,是天一觀的道長(zhǎng)赊琳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)砰碴,這世上最難降的妖魔是什么躏筏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮呈枉,結(jié)果婚禮上趁尼,老公的妹妹穿的比我還像新娘。我一直安慰自己猖辫,他們只是感情好酥泞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著啃憎,像睡著了一般芝囤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辛萍,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天悯姊,我揣著相機(jī)與錄音,去河邊找鬼叹阔。 笑死挠轴,一個(gè)胖子當(dāng)著我的面吹牛传睹,可吹牛的內(nèi)容都是我干的耳幢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼欧啤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼睛藻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起邢隧,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤店印,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后倒慧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體按摘,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年纫谅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炫贤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡付秕,死狀恐怖兰珍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情询吴,我是刑警寧澤掠河,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布亮元,位于F島的核電站但绕,受9級(jí)特大地震影響妨蛹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卡骂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一跃闹、第九天 我趴在偏房一處隱蔽的房頂上張望嵌削。 院中可真熱鬧,春花似錦望艺、人聲如沸苛秕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)艇劫。三九已至,卻和暖如春惩激,著一層夾襖步出監(jiān)牢的瞬間店煞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工风钻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留顷蟀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓骡技,卻偏偏與公主長(zhǎng)得像鸣个,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子布朦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 3. 類設(shè)計(jì)者工具 3.1 拷貝控制 五種函數(shù)拷貝構(gòu)造函數(shù)拷貝賦值運(yùn)算符移動(dòng)構(gòu)造函數(shù)移動(dòng)賦值運(yùn)算符析構(gòu)函數(shù)拷貝和移...
    王偵閱讀 1,790評(píng)論 0 1
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,506評(píng)論 1 51
  • 1.C和C++的區(qū)別囤萤?C++的特性?面向?qū)ο缶幊痰暮锰帲?答:c++在c的基礎(chǔ)上增添類是趴,C是一個(gè)結(jié)構(gòu)化語(yǔ)言涛舍,它的重...
    杰倫哎呦哎呦閱讀 9,478評(píng)論 0 45
  • 曹操死后劉備當(dāng)了皇帝,他跟手下的謀士一起商量好征討孫權(quán)唆途。但孫權(quán)的勢(shì)力太大了富雅,再加上那時(shí)的習(xí)俗還沒(méi)有達(dá)到完全兵精糧足...
    冰箱靜音99閱讀 188評(píng)論 0 1
  • 林深時(shí)見(jiàn)鹿 初心不忘
    后膩閱讀 248評(píng)論 1 6