2011-04-28 32 views
2

昨天我看到了一些有趣的編譯器行爲,我想我理解它爲什麼會發生,但我想確定。所以,我不會寫我的推理,只是事實。使用模板:首先解析運算符還是首先解析轉換?

請注意,這不是我輸入的錯別字vector而不是string。我這樣做是故意這樣編譯器就無法理解一個的std :: string是等它不得不四處搜尋找出我被+指哪運營商:

#include <vector> 
// #include <string> // intentionally commented out 

template <typename T> struct A 
{ 
    A() { }; 
    ~A() { }; 

    int m_member; 
}; 

template <typename T> A<T> operator+(double lhs, const A<T> &rhs); 

int main(int argc, char **argv) 
{ 
    std::string fullString = std::string("Hi ") + std::string("mom!"); 
} 

所以,我在MS Visual Studio 2005中遇到了一些編譯器錯誤。我只顯示了它們的一個子集。

1>.\test.cpp(21) : error C2784: 'A<T> operator +(double,const A<T> &)' : could not deduce template argument for 'const A<T> &' from 'std::basic_string<_Elem,_Traits,_Ax>' 
1>  with 
1>  [ 
1>   _Elem=char, 
1>   _Traits=std::char_traits<char>, 
1>   _Ax=std::allocator<char> 
1>  ] 
1>  .\test.cpp(16) : see declaration of 'operator +' 

...繼續錯誤...

1>.\test.cpp(21) : error C2784: 'std::_Vb_iterator<_MycontTy> std::operator +(_Vb_iterator<_MycontTy>::difference_type,std::_Vb_iterator<_MycontTy>)' : could not deduce template argument for 'std::_Vb_iterator<_MycontTy>' from 'std::basic_string<_Elem,_Traits,_Ax>' 
1>  with 
1>  [ 
1>   _Elem=char, 
1>   _Traits=std::char_traits<char>, 
1>   _Ax=std::allocator<char> 
1>  ] 
1>  C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(1800) : see declaration of 'std::operator +' 

...錯誤繼續...

1>.\test.cpp(21) : error C2784: 'std::_Vb_const_iterator<_MycontTy> std::operator +(_Vb_const_iterator<_MycontTy>::difference_type,std::_Vb_const_iterator<_MycontTy>)' : could not deduce template argument for 'std::_Vb_const_iterator<_MycontTy>' from 'std::basic_string<_Elem,_Traits,_Ax>' 
1>  with 
1>  [ 
1>   _Elem=char, 
1>   _Traits=std::char_traits<char>, 
1>   _Ax=std::allocator<char> 
1>  ] 
1>  C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(1695) : see declaration of 'std::operator +' 

...錯誤繼續...

1>.\test.cpp(21) : error C2784: 'std::_Vector_iterator<_Ty,_Alloc> std::operator +(_Vector_iterator<_Ty,_Alloc>::difference_type,std::_Vector_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_iterator<_Ty,_Alloc>' from 'std::basic_string<_Elem,_Traits,_Ax>' 
1>  with 
1>  [ 
1>   _Elem=char, 
1>   _Traits=std::char_traits<char>, 
1>   _Ax=std::allocator<char> 
1>  ] 
1>  C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(396) : see declaration of 'std::operator +' 

...錯誤繼續...

1>.\test.cpp(21) : error C2784: 'std::_Vector_const_iterator<_Ty,_Alloc> std::operator +(_Vector_const_iterator<_Ty,_Alloc>::difference_type,std::_Vector_const_iterator<_Ty,_Alloc>)' : could not deduce template argument for 'std::_Vector_const_iterator<_Ty,_Alloc>' from 'std::basic_string<_Elem,_Traits,_Ax>' 
1>  with 
1>  [ 
1>   _Elem=char, 
1>   _Traits=std::char_traits<char>, 
1>   _Ax=std::allocator<char> 
1>  ] 
1>  C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\vector(264) : see declaration of 'std::operator +' 

因此,編譯器四處搜索+意味着什麼,並抱怨說它無法推斷出適當的模板參數。我驚訝於兩件相關的事情,其中一個是它爲每個涉及模板的超載+運算符提供此錯誤。這告訴我,編譯器絕對沒有辦法排除這些+中的任何一個都沒有意義; 兩個,這是相關的,它不只是抱怨沒有合適的運營商存在。

我認爲這是一個學習如何實例化和編譯模板的機會。有沒有人有任何好的解釋或參考?

+1

哦,並且只是爲了編譯器甚至知道'std :: basic_string <...>'的評論。它包含在''通過''通過''。 :) – Xeo 2011-04-28 17:16:14

+0

+1這很有趣。我也想知道。 – 2011-04-28 17:16:52

回答

2

事實上,由於找不到匹配項,它使用錯誤來告訴您其實際找到的可能的運算符候選項。

例如,g ++的錯誤告訴你,它找不到運算符,然後提供相同的消息,但在「候選是:」形式而不是每個運算符一個錯誤。

它這樣做是爲了幫助:因爲它找不到匹配項,所以假設您可能實際上意味着任何可能的可用操作符。

+0

有幾個人回答,但是這是第一位的。謝謝。 – 2011-04-28 17:28:59

1

它不只是抱怨沒有合適的操作符存在。

這是一個簡單的愚蠢的編譯器行爲,如果這就是發生了什麼。當然,它應該首先告訴你什麼是錯的(即沒有合適的運營商存在),然後列出所有考慮的模板。

其中之一是,它會爲每個涉及模板的重載+運算符提供此錯誤。這告訴我,編譯器絕對沒有辦法排除這些+中的任何一個都沒有意義;

一般情況下,它不能做到這一點,因爲例如std::_Vector_iterator<_Ty,_Alloc>可能是一個基類的std::basic_string<>,這意味着一個操作符重載可能是可行的,扣得手。參數推導是編譯C++的階段,它將這些事情計算出來,而編譯器只是向您報告推論推論的結果。

+1

VC10確實報告沒有合適的運算符存在('錯誤C2676:binary'+':'std :: string'未定義此運算符或轉換爲預定義運算符可接受的類型)。它被報告在所考慮的過載列表的末尾,而不是之前,但至少有報道。 (我不知道OP的編譯器VC8是否也這樣做了;我沒有安裝任何地方檢查。) – 2011-04-28 17:20:04

+0

@James ohh謝謝檢查! – 2011-04-28 17:22:20

+0

的確如此:James:'1>。\ test.cpp(21):error C2676:binary'+':'std :: basic_string <_Elem,_Traits,_Ax>'沒有定義這個運算符或者是一個類型的轉換預定義的操作員可以接受「因爲有37個錯誤,所以我沒有那麼做。 – 2011-04-28 17:44:04

2

注意,這並不是說我已經包括vector,而不是string一個錯字。我故意這樣做,以便編譯器無法理解std :: string是什麼,所以它將不得不四處搜索以找出+指的是哪個運算符。

這是不正確的。編譯器確實知道std::string是什麼。舉個例子,下列程序編譯就好了(使用Visual C++ 2010,但它也應該在2005年的工作):++ 2005年至2010年

#include <vector> 

int main() { 
    std::string s; 
} 

當使用Visual C++(至少的Visual C,我可以」 t代表其他版本),包括<vector>也包括任何內部頭部聲明並定義std::basic_stringstd::string。這是C++語言標準所允許的。

但是,您顯然沒有得到std::string(或更準確地說,std::basic_string)操作數的operator+過載。爲了得到那些你必須包括<string>

編譯器完全知道什麼是std::string,但是當它試圖找到一個operator+過載兩個std::string對象,它失敗並報告所有的operator+重載,它認爲,但被拒絕。

+0

+1,謝謝。關鍵點似乎在你的最後一段。也就是說,如果它只能找到'operator +'的模板版本,那麼它會產生所有無法找到轉換的內容,並且這是故意做到的。然而,看起來如果'operator +'有非模板重載,那麼它只會抱怨一次。畢竟,我想這是一個功能。 – 2011-04-28 17:28:18

+0

你的回答節省了我的時間。MS糟糕的文件記錄(IMO)的其中一件事正是其中包括用於給定的一類或一組功能。我正在重複使用代碼,並不知道我需要 ...畢竟我已經有。非常感謝! – ChronoFish 2012-12-14 03:05:23

+0

@ChronoFish:''和''是兩個不同的標題:前者來自C標準庫;後者來自C++標準庫。除了相似的名字,它們完全不相關。哪些標題包含哪些其他標題基本上未指定。程序員需要包含正確的頭文件。例如,您可以從許多地方之一找出您需要包含哪個標頭 - [cppreference.com](http://en.cppreference.com/w/)。 MSDN也應該有這個文檔。 – 2012-12-14 03:26:50