在下面的示例中,Foo
沒有按照預期進行,但我無法弄清楚爲什麼允許編譯。使用參考作爲模板類型
我使用模板發現這一點,但typedef
顯示,其無關的模板。不用說,s
在這裏不是一個有效的字符串。我認爲構造Foo
返回值會產生編譯錯誤。
缺少什麼我在這裏?
在下面的示例中,Foo
沒有按照預期進行,但我無法弄清楚爲什麼允許編譯。使用參考作爲模板類型
我使用模板發現這一點,但typedef
顯示,其無關的模板。不用說,s
在這裏不是一個有效的字符串。我認爲構造Foo
返回值會產生編譯錯誤。
缺少什麼我在這裏?
首先,它沒有價值,這個問題實際上有模板沒有關係,因爲這個代碼編譯一個很好:
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
等)
這有什麼好做的模板,你會得到相同的結果如果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的新知識!
編輯問題到遠程模板是否合適(因爲2個人已經評論過)?或者我應該保持現狀? – JaredC
我認爲可以編輯它...這個問題很有意思,因此澄清它以刪除關於模板的紅鯡魚是有意義的。 –
@JaredC:我同意喬納森。當然,這也意味着正在編輯答案以考慮已更改的問題;) –
如果您調用'Foo(a);'並期望專業化'Foo ()'被觸發,那麼不會調用您的專業化。 –
WhozCraig
@WhozCraig我同意,我很絕望,因爲它沒有意義。 – JaredC
當然,如果你直接調用'Foo()',它確實會觸發,但這不是你真正想要的,毫無疑問。 –
WhozCraig