2010-11-12 54 views
7

在使用Microsoft VisualStudio 2008構建一個小示例程序的同時,我注意到傳遞給模板的類型的演繹有點奇怪。考慮下面的例子:爲什麼在推導類型時剝奪了模板參數的限定符?

template<class T> 
void f(T v) { 
    x; // trigger a compile error 
    (void)v; 
} 

template<class T> 
void g(T v) { 
    f(v); 
} 

void h() { 
    int i; 
    g<const int &>(i); 
} 

編譯使用cl /c foo.cpp產生一個編譯錯誤(如預期)這個例子。有趣的是'T'模板參數的值。下面是2008年的VisualStudio打印:

mini.cpp(3) : error C2065: 'x' : undeclared identifier 
     mini.cpp(9) : see reference to function template instantiation 'void f<int>(T)' being compiled 
     with 
     [ 
      T=int 
     ] 
     mini.cpp(14) : see reference to function template instantiation 'void g<const int&>(T)' being compiled 
     with 
     [ 
      T=const int & 
     ] 

注意如何在g,參數的類型是const int &但在f它只是int。很顯然,在實例化f模板時,參考常量部分被刪除,同時推導出要使用的類型。調整例如當使得f調用等

f<T>(v); 

類型是在兩個fgconst int &。這是爲什麼?這是指定的行爲?我暗中依靠v函數參數的類型傳遞給f,但顯然它不是。

+0

'C++'模板+ MSVC++ =糟糕的組合。 – 2010-11-12 12:40:39

+2

@Prasoon:GCC推導出相同的類型。當然,在GCC中,提問者的代碼會在'f'模板中觸發一個編譯錯誤,然後它會考慮實例化它,因爲GCC會正確執行兩階段編譯。 'x'不依賴於模板參數,所以應該在第一階段(如GCC)拒絕,而不是第二階段(如在MSVC中)。但是把'x'改成'v = 1;',很容易看到GCC沒有用'const int&'實例化'f',除非你在'g'中明確指定'f (v)'。 – 2010-11-12 12:45:31

回答

6

答案是,雖然可變v具有類型const int &,所述表達v是一個左值表達const int類型。 「如果一個表達式最初具有類型」對T的引用「(8.3.2,8.5.3),則在進行任何進一步分析之前,類型被調整爲」T「 ,表達式指定由引用表示的對象或函數,並且表達式是左值。「

「參數」是「在由函數調用表達式中的括號限定的逗號分隔列表中的表達式」(1.3.1)。因此,在14.8.2.1中:

  • 「呼叫的相應參數類型(稱爲A)」爲const int
  • 「如果A是cv限定類型,則A類型的頂級cv限定符將被忽略,因爲類型扣除」(因此,int)。
  • 「的推導過程試圖找到模板參數值,這將使演繹出等同於A」(所以T是int
+0

你可能是對的。 A和P的標準術語讓我完全糊塗= | – icecrime 2010-11-12 13:11:07

+0

@icecrime:我也是,這不是我熟悉的標準的一部分。我認爲對「P」的調整意味着如果'f'被聲明爲'template void f(const T v)',或'template void f(T&v)',那麼T將用於類型推導。不過,我不確定我是否正確理解它。 – 2010-11-12 13:14:04

+0

即使這不是100%正確,它也足夠接近。 「很顯然」,如果我們看看'v + v'這個表達式,每個人都會認爲它表現得像整數加法一樣。在那裏把'int&'與'int'區別對待是沒有意義的。 – MSalters 2010-11-12 13:59:12

1

http://accu.org/index.php/journals/409是一個相當廣泛的文章,但它解釋的過程。從模板參數中導出參數類型P,並將其與參數類型A進行匹配。相關部分是描述目標類型A如何從函數參數派生的地方:對於非數組類型,只是簡單地刪除引用。因此,如果參數的類型是int&,那麼目標類型A只是int

這是一個很簡單的原因:因爲標準告訴我們。基本原理是什麼?碰巧,這篇文章有一個腳註也指出了這一點。在你的例子中,typeid(v)==typeid(const int)。在非左值上下文中使用時,引用類型的行爲與非引用類型相似。

相關問題