測試方案模板 C 函式模板的偏特化

2021-10-12 04:46:10 字數 3927 閱讀 6957

c++標準並不支援函式模板偏特化,然而在實際開發中,我們確實需要對一些函式模板進行偏特化。本文將介紹幾種函式模板偏特化的通用方案。

偏特化是相對於全特化而言的,即只特化了部分模板引數,如下:

// 類模板偏特化demo

template class myvector

};template class myvector

};myvectorv1;

myvectorv2;

輸出結果:

normal version.

normal version.

partial version.

後面的乙個myvector是乙個偏特化版本,其只特化了allocator_t這乙個模板引數為defaultallocator。通過輸出結果也可以看出來,其中v1, v2使用上面的乙個類定義,而v3使用的是下面的特化版的類。

和類模板偏特化同樣的道理,我們嘗試去對乙個函式進行偏特化:

/// 函式模板偏特化demo

template void f(a a, b b)

template void f(a a, int b)

// 測試**

int a = 10;

double b = 12;

f(a, b);

f(a, a);

這段**的意圖很簡單,就是期望在調f()的時候,如果第二個引數是int,就走到下面乙個偏特化版本的f()裡。然後這段**編譯會出現如下錯誤:

func_partial_demo.cc:9:6: error: function template partial specialization is not allowed

void f(a a, int b)

void operator() ()

private:

a a_;

b b_;

};template class f

void operator() ()

private:

a a_;

int b_;

};// 測試**

int a = 10;

double b = 12;

f(a, b)(); // 輸出 normal version.

f(a, a)(); // 輸出 partial version.

當然這裡你不去實現operator()方法其實問題也不大,你可以繼續使用f作為方法名,然後呼叫的時候呼叫該物件的f方法即可。

c++標準雖然不支援函式模板的偏特化,但函式的過載顯然是支援的。使用標籤分發(tag dispatch)的方案就是通過函式實現不同的函式過載實現,根據不同實參型別選擇具體的函式實現,以達到函式模板偏特化的實現。

// 標籤分發demo

struct normalversiontag {};

struct intpartialversiontag {};

templatestruct tagdispatchtrait ;

template<>

struct tagdispatchtrait;

template inline void internal_f(a a, b b, normalversiontag)

template inline void internal_f(a a, b b, intpartialversiontag)

template void f(a a, b b) );

}// 測試**

int a = 10;

double b = 12;

f(a, b);

f(a, a);

上述測試**輸出結果為:

normal version.

partial version.

可以看到這種方案是利用函式過載的特性以達到根據實參型別篩選不同函式實現的能力。我們將這種實現稱為標籤分發。

c++20提供了concepts特性,concepts特性提出的動機是為了解決模板元程式設計過程中,編譯器給出的報錯資訊冗餘及編譯器不能很好的給出準確的出錯資訊的問題。你可以簡單的理解為concepts就是在模板元程式設計過程中需要使用者手動打的hints,來幫助編譯器知道你在元程式設計過程中的想法,進而可以更好地給你提供準確的資訊。下面看下,如何利用concepts輕鬆地實現該能力。

template void f(a a, b b) 

template requires std::integralvoid f(a a, b b)

// 測試**

int a = 10;

double b = 12;

f(a, b);

f(a, a);

毫無疑問上述的輸出結果還是和之前實現的一樣,符合預期。其中對於偏特化的版本其requires b型別為int型別,所以在f(a, a)的呼叫中,編譯器生成且直接匹配到這乙個偏特化的版本。不過再次提醒的是,concepts特性是c++20才支援的特性。

上述我們提到的三種不同的實現其實都是有各自的優缺點,第一種使用類偏特化的實現優點在於邏輯清晰,傳統的c++程式設計師都能夠輕易的理解和實現。第二種使用標籤分發的方案實際上是利用函式過載達到函式模板偏特化的效果,實現上有一點繞彎,但標籤分發的方案是c++標準委員會推薦的一種方法,所以以前在一段時間內開發者所使用的方案。第三種concepts的方案是依賴於c++20,這種方案**最為簡潔和直觀,從c++原語上提供了編譯器型別要求和型別選擇的能力。毫無疑問,未來隨著c++20的普及和廣泛使用,concepts將是解決這類問題的通用方案。

另外這個鏈結給出了乙個使用標籤分發實現的函式模板偏特化的實際開發例子。其中呼叫的internalcaller()時會根據最後乙個引數tag進行標籤選擇不同的實現版本。

通過前面我們了解到函式模板不能直接被偏特化,那麼到底為什麼標準c++不支援函式模板偏特化呢?簡而言之是因為模板特化版本不參與函式的過載抉策過程,因此在和函式過載一起使用的時候,可能出現不符合預期的結果。因此標準c++禁止了函式模板的偏特化。那麼有人可能提出疑問,既然c++從語法上就禁止使用函式模板的偏特化,那麼為何我們還去做這件事情,豈不是矛盾?其實仔細思考,是不矛盾的。c++禁止的原因是在於函式模板偏特化和函式過載決策的矛盾,而我們在上述的幾種實現方案中,都很顯式地避開了函式過載的問題。方案1中使用的是類模板偏特化,沒有函式過載問題;方案2中使用的就是函式過載本身來作為決策依據;而方案3中,concpets使用在函式模板之上,本身就是利用concepts實現函式的過載,即該過程本身是乙個函式過載的決策過程,因此也不存在任何問題。

這裡給出一些相關的資料供大家自行思考。

c++核心準則: t.144: don't specialize function templates

herb sutter: why not specialize function templates?

a draft proposal proposed wording for concepts. 14.5.6.1小節

stack overflows: why function template cannot be partially specialized?

stack overflows: partial specialization of function templates

函式模板「偏特化」 (C )

模板是c 中很重要的乙個特性,利用模板可以編寫出型別無關的通用 極大的減少了 量,提公升工作效率。c 中包含類模板 函式模板,對於需要特殊處理的型別,可以通過特化的方式來實現特定型別的特殊操作。最近工作中,需要處理cont這種復合型別和t這種自定義型別的模板特化,因為cont型別有五種左右需要特殊處...

C 類模板 函式模板全特化 偏特化的使用

一 類模板全特化 偏特化 pragma once include程式設計客棧 include template class tc void funtest template class tc void funtest template void tc funtest main.cpp include...

C 模板 模板特化 模板偏特化

模板是c 的乙個重要特性 使用模板 可以極大的減少類似功能 的編寫 這可以看做是c 相較於c的進步 因為這一特性在c中是不容易達到的 語言層面不支援 模板的關鍵字是 template 簡單的模板應用 template class test int main 使用模板的類在例項化時需要指明模板引數型別...