2012-10-06 81 views
6

不知何故,我喜歡這些「最短」的程序顯示(基本?)問題。當在VS2008中測試一些模板代碼時,這個錯誤出現了(它也被VS2010和VS2012證實,見下文):STL的VS編譯器錯誤C2752(「多個部分專業化匹配」)

c:\ program files(x86)\ microsoft visual studio 9.0 \ vc \ include \ xmemory(225):錯誤C2752: '的std :: _ Ptr_cat_helper < _T1,_T2>':一個以上的部分特化的模板參數列表

with 
    [ 
     _T1=const float (**), 
     _T2=const float (**) 
    ] 

我可以歸結問題有以下三個行相匹配:

#include <vector> 
typedef float TPoint[3]; 
std::vector<TPoint const*> points; // error C2752 

注意,以下是一切ok

#include <vector> 
#include <list> 
typedef float TPoint[3]; 
// these similar usages of TPoint are all ok: 
std::vector<TPoint*> points; // no error 
TPoint const* points1[2]; 
std::list<TPoint const*> points2; 

我試圖通過結構_Ptr_cat_helper提供額外的模板spezializations修復xutility - 沒有運氣。任何想法出了什麼問題?或者如何解決而不會丟失const

+1

還沒有安裝VS在我面前,但它與海灣合作委員會的工作。您可能在標準庫中找到了一個錯誤。 –

+0

升級VS目前是不可能的:我們依賴於來自其他團隊的dll(使用MFC組件)......但是,如果上面的三行代碼在VS2010上編譯將會很好聽 – coproc

+0

對不起,它不能編譯,這就是爲什麼我刪除了該評論。 :儘管這個矢量的元素應該是什麼,但這並不完全清楚。一個指向三個const Float元素的數組的指針? – Xeo

回答

8

問題是確實是在一個部分特歧義:

在內部,該分配器使用一些元編程(_Ptr_cat),以確定是否析構函數是對矢量的元素將被稱爲(或什麼也不做)。這個元編程試圖通過使用部分專業化來區分某些情況。 _Ptr_cat使用_Ptr_cat_helper這是專門用於矢量的分配器的指針類型 - 矢量的value_typeTPointer const* == const float (*)[3],所以該矢量的分配器有一個指針類型const float(**)[3]

當使用std::vector < const float(*)[3] >,錯誤消息包含[3]部分,而使用std::vector < TPoint const* >,所述[3]不顯示o.O

_Ptr_cat預計兩個相同類型的模板參數具有可能不同的c-限定符,例如float*, float const*。 現在,這兩種輸入類型都是const float (**)[3]。 MSVC不明確地將其解決爲_Ptr_cat_helperTy**, Ty const**和/或Ty**, Ty**的專業化。我通過編寫一個模仿_Ptr_cat_helper(只是普通模板,不涉及Std Lib)的部分專業化的小例子來驗證。

但是,我無法解釋爲什麼會發生這種情況。奇怪的是,在僅使用一個專門化參數設置示例時沒有歧義 - 如預期的那樣,const float(**)[3]被解析爲Ty const**並且Ty = float const[3]

感謝Peter Alexander,我也用g ++試過我的簡單例子(2個模板參數),它按預期工作,沒有歧義。也許這可能是一個編譯器問題?

讓我提出一些解決方法:

  • 如果你真的要修改的MSVC標準庫,你可以添加一個專業化_Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] >它完全適合和解決該不確定性。不幸的是,你必須明確提供維度(3)。
  • 請勿使用陣列此處。使用std::array(可在VS08 tr1)或結構或純指針(float const*而不是float const[3]
  • 使用一個簡單的包裝:

    template < typename T > struct wrapper { T wrapped; } 
    std::vector < wrapper <TPoint> const* > m; 
    

    工作正常,我。

編輯:這裏是我使用的示例:

#include <typeinfo> 
#include <iostream> 

template < typename T1, typename T2 > 
struct Spec 
{ 
    static const char* check() { return "plain"; } 
    typedef void Value; 
}; 

#define MAKE_SPEC(ARG0, ARG1) \ 
template < typename T > \ 
struct Spec < ARG0, ARG1 > \ 
{ \ 
    static const char* check() { return #ARG0 ", " #ARG1; } \ 
    typedef T Value; \ 
} 

MAKE_SPEC(T**, T**); 
MAKE_SPEC(T**, T const**); 
// can do more, but need not to.. 

int main() 
{ 
    typedef Spec < const float(**)[3], const float(**)[3] > MySpec; 

    std::cout << MySpec::check() << " -- " << typeid(MySpec :: Value).name(); 
} 
+0

'也許這可能是一個編譯器問題' - 我期望它成爲一個圖書館問題。仍然+1分析 – sehe

+0

由於我寫的一個小例子使用g ++編譯得很好,而不是MSVC,所以我認爲這不是庫問題。我已經遇到了一些(確認的)編譯器錯誤,並且知道這些是非常罕見的 - 因此試圖保守地制定它。 – dyp

+1

咦?庫的實現是完全不同的......我並不是說它不能成爲編譯器問題,但直到你,例如,顯示GCC + STLPort編譯這個,而MSVC + STLPort沒有基礎,但沒有基礎 – sehe