2012-05-17 74 views
32

我有一些C++代碼在沒有-fpermissive選項時不再編譯。 這是我無法分享的專有代碼,但我認爲我已經能夠提取一個簡單的測試用例來演示問題。下面是來自克輸出++C++模板中的名稱查找

template_eg.cpp: In instantiation of 'void Special_List<T>::do_other_stuff(T*) [with T = int]': 
template_eg.cpp:27:35: required from here 
template_eg.cpp:18:25: error: 'next' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] 
template_eg.cpp:18:25: note: declarations in dependent base 'List<int>' are not found by unqualified lookup 
template_eg.cpp:18:25: note: use 'this->next' instead 

因此,這裏是產生問題的代碼:

template<class T> class List 
{ 
     public: 
     void next(T*){ 
      cout<<"Doing some stuff"<<endl; 
     }  
}; 

template<class T> class Special_List: public List<T> 
{ 
    public: 
     void do_other_stuff(T* item){ 
       next(item); 
     }  
}; 


int main(int argc, char *argv[]) 
{ 
    Special_List<int> b; 
    int test_int = 3; 
    b.do_other_stuff(&test_int); 
} 

我不是試圖找出如何解決代碼,使其重新編譯。 這只是一個改變下一個(項目)這個 - >下一個(項目) 的問題我試圖更好地理解爲什麼這個改變是必要的。 我在這個頁面發現了一個解釋:http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html 儘管這個解釋很有用,但我仍然有一些問題。不應該這樣的事實,即我的函數採用T *(指向類型T的指針)使其依賴於模板參數。 在我自己的措辭中,編譯器(gcc 4.7)不應該能夠找出next()函數在基類List中嗎? 爲什麼有必要在每個這樣的電話前加上這個 - >? 我注意到叮噹聲3.1表現出相同的行爲,所以我認爲在C++標準中有一些要求這種行爲的要求。任何人都可以提供一個理由嗎?

回答

50

的問題在於模板在兩次傳遞中被處理(根據標準,VS會另有處理)。在第一遍中,在類型替換之前,查找並檢查不依賴於模板參數的所有內容。一旦類型被替換,則依賴名稱將在第二遍中解決。

現在,在第一遍中沒有任何內容表明next依賴於模板參數,因此它需要在類型替換之前解析。現在,由於基本類型是模板化在當前模板的模板參數上的,因此編譯器無法查看它(它可能專用於某些類型,並且不知道我們使用哪種類型的實例化模板,我們無法知道哪些特化使用,即基地取決於T,我們正在檢查之前知道T)。

加入this->的特技變成next成從屬名稱,而這又意味着,查找被延遲,直到第二次通過,其中T是已知的,並且因爲T是已知的,List<T>還已知並且可被查找成。


EDIT:一個重要的細節在上面的應答的措辭缺少的是第二階段查找(類型的取代基之後),只會增加參數依賴查找過程中發現的功能。也就是說,如果next是與T關聯的名稱空間中的自由函數,則會發現它,但它是基礎上的成員,對於ADL在T上不可見。

+3

+1。簡短的解釋。 – Nawaz

+0

謝謝!所以,如果我理解正確,接下來的論點是不相關的。 next()採用依賴參數,不會使next()相關的事實? – Avatar33

+0

@ Avatar33:'next()'是相關的,但第二階段查找只會添加來自ADL的結果,其中不包含基數成員。我可能不得不重新回顧答案的形式...... –

5

如果您基類是一個模板實例,那麼就沒有辦法知道next是指名稱中的基類 - 畢竟,這個名字甚至不必存在(想想特)!因此,不得不向編譯器聲明next實際上是一個類成員,通過將this->List<T>::nextusing List<T>::next;添加到派生類模板中。

+0

這個最後的'using'技術在基類中使用''''typedef'聲明的情況下非常有用,你不能使用'this->'。你可以明確地使用'typename Base :: MyType',無論你引用哪個類型,或者更方便的,你可以在派生類中聲明'使用typename Base :: MyType;'。 – Jeremy

8

你需要寫this->爲:

this->next(item); 

這裏this->部分是必需的,因爲next()模板基地繼承成員,如果你仔細閱讀錯誤消息,建議有本身:

template_eg.cpp:18:25:注:在從屬鹼'List<int>'聲明不被不合格查找
發現template_eg.cpp:18:25:注:使用'this->next'代替

閱讀這篇文章,這在C++解釋兩階段名稱查找: