2012-10-06 9 views
6

In qualche modo mi piacciono questi programmi "più corti" che mostrano un problema (fondamentale?). Durante il test del codice modello in VS2008 questo errore si presentò (è stato confermato anche per VS2010 e VS2012, vedi sotto):Errore del compilatore VS C2752 ("più di una corrispondenza di specializzazione parziale") in STL

c: \ program files (x86) \ Microsoft Visual Studio 9.0 \ VC \ include \ xmemory (225): l'errore C2752: 'std :: _ Ptr_cat_helper < _T1, _T2>': più di una specializzazione parziale corrisponde all'elenco dei modelli argomenti

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

ho potuto ridursi il problema per le seguenti tre righe :

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

Nota che il seguente è tutto 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; 

Ho cercato di risolvere xutility fornendo spezializations template aggiuntivi per struct _Ptr_cat_helper - senza fortuna. Qualche idea cosa va storto? O come lavorare senza perdere lo const?

+1

Non hai ancora un VS installare di fronte a me, ma funziona con GCC. Potresti aver trovato un bug nella loro lib standard. –

+0

L'aggiornamento a VS non è attualmente possibile: dipendiamo da dll (utilizzando componenti MFC) di altri gruppi ... Ma sarebbe bello sentire se le tre righe sopra compilarono su VS2010 – coproc

+0

Scusa, non viene compilato, motivo per cui I rimosso quel commento. :/Non è del tutto chiaro quale sia l'elemento del vettore, però. Un puntatore a un array di tre elementi di const float? – Xeo

risposta

8

Il problema è infatti un'ambiguità in una specializzazione parziale:

Internamente, l'allocatore utilizza alcuni metaprogrammazione (_Ptr_cat) per determinare se il dtor si chiamerà sugli elementi del vettore (o fare nulla). Questa metaprogrammazione cerca di differenziare alcuni casi usando la specializzazione parziale. _Ptr_cat utilizza _Ptr_cat_helper che si sta specializzando sul tipo di puntatore dell'allocatore del vettore: il vettore value_type è TPointer const* == const float (*)[3], quindi l'allocatore del vettore ha un tipo di puntatore const float(**)[3].

Quando si utilizza std::vector < const float(*)[3] >, il messaggio di errore contiene la parte [3], mentre l'uso di std::vector < TPoint const* >, il [3] non viene visualizzata ò.ò

_Ptr_cat si aspetta due argomenti di modello dello stesso tipo con possibilmente diverso c-qualificazione, per esempio float*, float const*. Ora, i due tipi di input sono entrambi const float (**)[3]. MSVC li risolve ambiguamente con le specializzazioni di _Ptr_cat_helper: Ty**, Ty const** e/o Ty**, Ty**. Ho verificato che scrivendo un piccolo esempio che imita la specializzazione parziale di _Ptr_cat_helper (solo modelli semplici, non è coinvolto Std Lib).

Tuttavia, non riesco a spiegare perché questo accada. Stranamente, non c'è alcuna ambiguità quando si imposta un esempio usando un solo parametro di specializzazione - const float(**)[3] è risolto a Ty const** con Ty = float const[3] come previsto.

Grazie a Peter Alexander, ho anche provato il mio semplice esempio (2 parametri template) con g ++, e ha funzionato come previsto, senza ambiguità. Forse questo potrebbe essere un problema con il compilatore?

Vorrei proporre alcune soluzioni:

  • Se davvero si vuole modificare il lib standard di MSVC, si potrebbe aggiungere una specializzazione _Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] > che si adatta esattamente e risolve l'ambiguità. Sfortunatamente, devi fornire la dimensione esplicitamente (3).
  • Non utilizzare gli array qui. Utilizzare std::array (disponibile in tr1 in VS08) o strutture o puntatori semplici (float const* invece di float const[3])
  • utilizzare un semplice involucro:

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

    funziona bene per me.

Edit: ecco l'esempio che ho usato:

#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

'Forse questo potrebbe essere un problema del compilatore' - Mi aspetterei che sia un problema di libreria. Ancora +1 per analisi – sehe

+0

Come il piccolo esempio che ho scritto compila bene con g ++ e non con MSVC, concludo che questo non è un problema di libreria in primo luogo. Ho già riscontrato alcuni bug del compilatore (confermati) e so che questi sono davvero rari, quindi cerco di formularlo in modo conservativo. – dyp

+1

Eh? Le implementazioni della libreria sono completamente diverse ... Non sto dicendo che non può essere un problema del compilatore, ma fino a quando, ad esempio, non mostri GCC + STLPort per compilarlo, mentre MSVC + STLPort non hai ancora poche basi. – sehe

Problemi correlati