2014-10-01 48 views
5

我今天看到以下類型的構造中的一些代碼:爲const char數組模板參數尺寸與字符指針

template<unsigned int N> unsigned int f(const char (&a)[N]); 

是否有這有任何合理的點滿有:

unsigned int f(const char *a); 

我依稀理解後者的指針共享含義,但是它真的很糟糕,需要用一個兩倍大小的不明確代碼來替換它?

(不幸的是,我不能叫代碼的作者,否則我會)

+0

在第二個例子中'a'指向什麼?一個'int'?一個簡單的數組?一個C字符串?一個空終止的數組?看到我的觀點? – Shoe 2014-10-01 11:08:14

回答

11
的大小

傳遞任何原料指向函數的目的是呼叫者有一些想法:

  • 什麼它指向。
  • 它指向多少個。

作爲輸入參數的C樣式字符串具有後面的推斷,因爲假設通過到達空字符結束符來判斷「有多少」。

但是,如果你是而不是傳遞一個C風格的字符串?如果它僅僅是一個零或多個char值的序列呢?好吧,如果是這樣的話,那麼:

void f(const char *s) 
{ 
    // how many char does s refer to? 
} 

的邏輯演繹是要做到這一點:

void f(const char *s, std::size_t N) 
{ 
    // Now the caller is telling us there are N chars at s 
} 

,這並不少見可言,儘管錯誤的,如果主叫方的電位點傳遞給我們錯誤的長度(從不說永不)。

但是,如果有什麼辦法可以將實際變量類型中的數據傳遞給使用通過非類型模板參數推導的函數?如果調用者使用固定數組調用我們會怎麼樣?

template<std::size_t N> 
void f(const char(&ar)[N]) 
{ 
    // we know the caller is passing a const-reference to a 
    // char array declared of size N. The value N can be used 
    // in this function. 
} 

現在我們知道我們列表中的兩個項目:「什麼」和「多少」。此外,我們現在可以提供模板功能和超載,並有提供給我們的兩個世界:

// length specified implementation 
void f(const char *s, std::size_t N) 
{ 
    // caller passed N 
} 

// fixed buffer template wrapper 
template<std::size_t N> 
void f(const char(&ar)[N]) 
{ 
    f(ar,N); // invokes length-specified implementation from above. 
} 

而且兩個以下將工作:

int main() 
{ 
    char buff[3]; 

    f(buff,3); 
    f(buff); 

} 

因此,如何爲這個好?因爲下面將標誌一個編譯器錯誤,因爲沒有配套的實施可以發現:

int main() 
{ 
    char buff[3]; 
    const char *ptr = buff; 
    f(ptr); // ERROR: no matching function f(const char *) 
} 

總之是協助提供我們的項目列表兩個項目給被叫方的通用技術:「是什麼」和每次使用固定長度的本地數組作爲輸入參數時,「多少」,而不必長時間使用sizeof(ar)/sizeof(*ar)

好運。

2

模板版本需要一定大小的數組。指針版本只接受一個指針,沒有任何指針指向的數據大小的概念。

1

template中實例化的N每個不同的值(所以有產生額外的機器代碼),但裏面f它是免費使用其N知識做什麼是非常有用的(如進程項的權數a,相應大小它可能需要的另一個字符數組)。您必須查看f以瞭解N是否實際使用,以及是否有用。對於非模板版本,調用者不提供數組/數據大小,所以沒有提供相應的信息(如果數據a指向的長度是可變的,那麼f將不得不依靠其他方式來知道有多少數據存在,例如strlen()花時間搜索終止的NUL)。

+0

你的strlen例子是錯誤的。無論如何,如果*真實*字符串大小小於數組大小> o < – ikh 2014-10-01 11:07:48

+0

@ikh:這不會使我的示例*錯誤* - 這是支持的用法和模板的問題形式通常是完成的*正是因爲*'N'值在這種用法中是有意義的,而不依賴於'strlen'等等(即使偶爾僅通過提供有用的上限)。 – 2014-10-01 11:19:02

3

指針不保留信息,不管它們是指向單個對象還是指向數組的第一個對象。所以,如果你例如功能

unsigned int f(const char *a); 

表達

sizeof(a)/sizeof(*a) 

身體內寫上你將只能得到指針本身的大小。雖然如果你將在函數體內使用相同的表達式,你將得到數組的大小(當然你可以使用簡單的N值)。

因此,當使用第二種方法有兩個參數,其中,第二個參數指定數組

unsigned int f(const char *a, size_t n); 

的大小考慮一個情況,當你需要儘可能傳遞的字符數組追加話,通常這樣的函數聲明與其他字符串的參數(讓我們假設限定符常量不存在)。當您使用第二個聲明時,即使應用於指針的函數strlen也不會幫助您確定原始字符串是否足夠大並且可以追加。在第一種方法中,您可以使用表達式N - strlen(a)來確定陣列中是否有足夠的空間。

3
template<unsigned int N> unsigned int f(const char (&a)[N]); 

該函數模板通過引用接受數組,這意味着當直接使用靜態分配的C數組時,該函數知道編譯時的數組大小。

unsigned int f(const char *a); 

這裏所有的函數都知道它已經被賦予了一個指向const char的指針。所以如果你想用它來操作一個數組,它將不得不把數組的大小作爲一個額外的參數,因爲沒有辦法從指針單獨檢索這個信息。

1

有兩個原因來使用:

  • 它是不可能被提交給該模板函數什麼,但C風格的數組。所以,用指針調用該方法將會是一個編譯錯誤。
  • 在模板函數你得到的數組的大小,在編譯期間評估

所以,這樣的:

const char* p="abc"; 
f(p); 

導致編譯失敗:

garbage.cpp:39:5: error: no matching function for call to ‘f(const char*&)’ 
    f(p); 
    ^
garbage.cpp:39:5: note: candidate is: 
garbage.cpp:21:39: note: template<unsigned int N> unsigned int f(const char (&)[N]) 
template<unsigned int N> unsigned int f(const char (&a)[N]) 

而,這個:

f("abc"); 

是好的,你得到這個數組確定爲編譯常數