2012-12-17 178 views
7

在下面的示例中,Foo沒有按照預期進行,但我無法弄清楚爲什麼允許編譯。使用參考作爲模板類型

​​

我使用模板發現這一點,但typedef顯示,其無關的模板。不用說,s在這裏不是一個有效的字符串。我認爲構造Foo返回值會產生編譯錯誤。

缺少什麼我在這裏?

+0

如果您調用'Foo (a);'並期望專業化'Foo ()'被觸發,那麼不會調用您的專業化。 – WhozCraig

+0

@WhozCraig我同意,我很絕望,因爲它沒有意義。 – JaredC

+0

當然,如果你直接調用'Foo ()',它確實會觸發,但這不是你真正想要的,毫無疑問。 – WhozCraig

回答

6

首先,它沒有價值,這個問題實際上有模板沒有關係,因爲這個代碼編譯一個很好:

typedef std::string& T; 
T Foo(int& i) { 
    return T(i); 
} 

認爲這個編譯的原因是return語句相當於

return reinterpret_cast<T>(i); 

萬一T恰好是參考成員。 ......當然,這是編譯的:你答應你知道你在做什麼,並請編譯器友好地相信你。

行,發現它在5.2.3 [expr.type.conv]段落1:

...如果表達式列表是一個單一表達式,類型轉換表達式是等效(在definedness,如果在含義中定義)與相應的演員表達(5.4)。 ...

...和5.4 [expr.cast]段落4:

由[其他形式的管型]進行轉換一個的reinterpret_cast(5.2.10)[...]可以使用顯式類型轉換的強制符號來執行。 [...]

(在省音涵蓋涉及用戶定義類型的情況下,內置的類型轉換,轉換const等)

+0

你可以擴展*爲什麼*在這種情況下調用'reinterpret_cast'時T是一個參考? – JaredC

+0

哇,這很微妙,特別是在使用模板時。在這種情況下,我看到一個關於禁止參考類型'T'的後續問題... – JaredC

+0

請參閱我的答案的結尾以瞭解如何禁止它 –

5

這有什麼好做的模板,你會得到相同的結果如果T只是爲std::string&而非推導模板參數的類型定義:

#include <string> 

typedef std::string& T; 

T Foo(int & i) 
{ 
    return T(i); 
} 

int main() 
{ 
    int a = 1; 
    std::string & s = Foo(a); 
} 

迪特馬爾的回答讓我意識到這可以進一步簡化爲:

#include <string> 

typedef std::string& T; 

int main() 
{ 
    int a = 1; 
    std::string & s = T(a); 
} 

其中T(a)是一樣的鑄造(T)a(std::string&)a其中(按5.4 [expr.cast]的規則)將做一個const_cast如果這是有效的(這是不)或static_cast如果這是有效(它不是)或static_cast後跟一個const_cast如果有效(不是)或reinterpret_cast如果有效(它是)或reinterpret_cast後面是const_cast如果是有效的,否則表情不合格。

那麼作爲迪特馬爾說,這是一樣做一個reinterpret_cast,即

std::string & s = reinterpret_cast<std::string&>(a); 

我覺得很奇怪,原來的代碼編譯,但因爲它是同上面的內容,它允許編譯。雖然使用演員的結果是未定義的行爲。

爲避免出現T(a)等同於強制轉換的意外,請使用新的C++ 11統一初始化語法T{a},該語法始終是初始化語句,而不是轉換表達式。

偉大的問題,調查和回答它顯示了我以前沒有意識到的一個新問題,這要歸功於JaredC和Dietmar的新知識!

+0

編輯問題到遠程模板是否合適(因爲2個人已經評論過)?或者我應該保持現狀? – JaredC

+0

我認爲可以編輯它...這個問題很有意思,因此澄清它以刪除關於模板的紅鯡魚是有意義的。 –

+0

@JaredC:我同意喬納森。當然,這也意味着正在編輯答案以考慮已更改的問題;) –

相關問題