2011-06-20 62 views
5

我想將自己的lib從Visual Studio移植到GNU/Linux上的g ++,並且我遇到了一些模板編譯問題。事實上,在Visual C++中,只有在代碼中明確使用模板時,纔會生成模板,但似乎(從我的錯誤中)g ++會在模板首次使用之前對其內容進行評估。這將導致以下錯誤:如何讓g ++模仿MSVC++的模板實例化行爲?

error: incomplete type ‘X’ used in nested name specifier 

...因爲我包含模板代碼後,一些類,而不是之前。由於交叉使用衝突,我正在這樣做。

綜上所述,似乎Visual C++不會嘗試解析模板的使用內容,並且g ++會盡快解析。

class MyClass; 
template<class _Ty> 
void func(MyClass* a_pArg) 
{ 
    a_pArg->foo(); 
}; 

(不使用_Ty但沒關係,這只是問題的解釋)

在這種情況下的Visual C++編譯會(即使MyClass沒有預先聲明)而g ++不會,因爲MyClass尚未完全聲明。

有沒有辦法告訴g ++只在使用時實例化模板?

+0

只是要清楚;你是說你*聲明* MyClass,然後定義函數模板,然後定義* MyClass *,然後最終實例化模板? –

+1

@Juicebox:唷!在這個問題上做了一些手術。如果我破壞了任何東西,請告訴我。 :) –

+5

@Juicebox:請注意,使用以下劃線開頭的名稱(例如'_Ty')是一個壞主意,因爲它們在很多情況下都是爲實現而保留的。 –

回答

9

不,這就是兩階段查找的工作方式。 MSVC實現它是錯誤的,它幾乎跳過了第一個階段,它在定義點解析模板。 MSVC只在這裏進行一些基本的語法檢查。在第二階段,在實際使用該模板時,只應檢查相關名稱。 MSVC在這裏進行所有類型的解析。 GCC正確執行兩階段查找。

在你的情況下,因爲MyClass不是模板參數,它可以在第一階段檢查它。你只需需要在此之前包括你的課程標題。

+0

雖然我感到困惑 - 但它似乎比在一個階段完成了多少工作更深刻:MSVC必須允許模板化代碼「看到」按順序出現但在時間之前出現的事物。 – Owen

+0

@Owen:更大的問題是在第一階段沒有完成多少工作**。在MSVC進行第二階段時,「MyClass」碰巧是一個完整的類型,但事實是標準要求'MyClass'在_first_階段需要是一個完整的類型,因爲它不是依賴類型。 – ildjarn

1

正如在另一個答案中指出的那樣,gcc在第一個查找階段查找非依賴名稱是正確的,VC++將大多數檢查轉移到第二階段(這是不正確的)。爲了修復你的代碼,你不需要搜索一些破碎版本的gcc。你需要分開聲明和實現(至少對於非依賴名稱)。使用你的榜樣,

// provide declarations 
class MyClass; 

template<class T> 
void func(MyClass* a_pArg); 

// provide definition of MyClass 
class MyClass 
{ 
    // watever 
}; 

// provide definition of func 
template<class T> 
void func(MyClass* a_pArg); 
{ 
    a_pArg->foo(); 
}; 
1

如果你願意,而不是使用GCC鐺,鐺支持-fdelayed-template(專用於在分析結束時執行模板實例化),通過特別設計的編譯MSVC代碼-fms-extensions期權的隱含(和許多怪癖)。根據Francois Pichet,誰領導CLang努力完全編譯MSVC代碼(並且實際上完成了大部分代碼),CLang應該能夠在大約2到3個月的時間內解析所有的MFC代碼,只有幾個剩下的不平凡的問題。已經大部分MFC已經被正確解釋(即,解釋爲VC++)。

0

Visual C++默認不實現標準指定的兩階段查找。

但是,在Visual Studio 2015中使用/ Za選項看起來像兩階段查找稍好一些。也許你可以通過在某些情況下添加/ Za選項來模仿GCC模板實例化行爲來做相反的事情。