2013-02-07 31 views
6

下面的代碼編譯(gcc 4.7.2或icc 13)併產生「1 2」輸出。這意味着const限定符被丟棄,即。即,f<int&>具有參數類型int&C++ 98/03引用崩潰和cv限定符

爲什麼發生?據我瞭解,根據§14.3.1.4:

如果模板實參爲模板參數T名稱的類型「參考CV1S」,企圖製造型「參考CV2T」創建類型‘參考CV12S’,其中CV12是CV-合格音響ERS CV1CV2的聯合。冗餘的cv-quali fi er被忽略。

const不應該被丟棄。下面是代碼:

#include <iostream> 
using namespace std; 

template <typename T> 
void f(const T& t) 
{ 
    t++; 
} 

int main() 
{ 
    int a = 1; 

    cout << a; 
    f<int&>(a); 
    cout << ' ' << a << endl; 

    return 0; 
} 
+4

我無法在C++ 98或C++ 03中找到該報價。 §14.3.1是「模板類型參數」,沒有小節或第4段。 –

回答

4

GCC 4.7.2不指定的標誌-std=c++98是當編譯此。事實上,在C++ 98(以及C++ 03)中,對引用的引用不會崩潰。

試圖實例f<int&>,其中T = int&,產生以下函數簽名(這裏我故意切換參數類型Tconst說明符,這是允許的,因爲const T&的位置是一樣的T const&):

void f(int& const& t) // ERROR: reference to reference is illegal 

上述內容在C++ 98和C++ 03中都不合法。一致的是,這是你從GCC 4.7.2得到錯誤:

Compilation finished with errors: 
source.cpp: In function 'int main()': 
source.cpp:15:14: error: no matching function for call to 'f(int&)' 
source.cpp:15:14: note: candidate is: 
source.cpp:5:6: note: template<class T> void f(const T&) 
source.cpp:5:6: note: template argument deduction/substitution failed: 
source.cpp: In substitution of 'template<class T> void f(const T&) [with T = int&]': 
source.cpp:15:14: required from here 
source.cpp:5:6: error: forming reference to reference type 'int&' 

不過,如果你使用-std=c++11標誌,則編譯器執行基準實例化模板時崩潰:左值引用一個左參考變成左值參考:

void f(int& const& t) == void f(int& t) 

這裏const預選賽被放棄了,因爲它適用於參考,而不是引用的對象。由於引用不能被重新分配,它們本質上是const,這就是爲什麼const被認爲是多餘的並被刪除的原因。有關說明,請參閱this Q&A on SO

這產生一個左值引用的左值引用,它將解析爲一個簡單的左值引用。因此,右側的簽名被實例化。

以上是解決f<int&>(a)問題的可行方案,因此編譯時無誤。

+0

void f(const int&t){t ++; }'編譯?它修改't'這是一個常量引用。 – Kleist

+0

@Kleist:恩,你說得對。讓我調查 –

+0

默認情況下,上面的代碼已經在gcc中作爲擴展工作了一段時間(它在4.1的默認模式下編譯,但如果您要求使用'-ansi',則會失敗) –

4

這裏是1770,其中有問題的報價似乎來源於:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html

14.3.1 - 模板類型參數

-4-如果一個模板參數的模板 - 參數T命名類型「lvalue-reference to cv1 S」,嘗試創建類型「(左值或右值)引用cv2 T」創建類型「lvalue-reference to cv12 S」,其中cv12是cv-qualifiers cv1和cv2。如果模板參數將類型「rvalue-reference to cv1 S」命名,則嘗試創建「cv2 T的左值引用」類型將創建類型「左值對cv12 S的引用」。如果模板參數將類型「rvalue-reference to cv1 S」命名爲「創建類型」rvalue-reference to cv2 T「,則會創建類型」rvalue-reference to cv12 S「。冗餘的cv限定符將被忽略。

這裏是2118,其中報價已經被剔除:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html

14.3.1 - 模板類型參數

-4-如果一個模板參數爲模板 - 參數T命名類型「對cv1 S的引用」它是對類型A的引用,嘗試創建類型「引用cv2 T」 「對cv T的左值引用」創建類型「對cv12 S的引用」,其中cv12是cv限定符cv1和cv2的並集。冗餘cv修飾符被忽略「左值參考A」,而試圖創建類型「右值引用到CV T」創建類型T

你所引用似乎是過時的寫法。

+0

好發現!.... –

+0

注意:在最終版本的C + +11,最後是8.3.2/5(即dcl.ref部分的一部分,不再是temp.arg.type)。除了名字之外,措辭沒有改變。 – jogojapan