2012-10-06 6 views
6

De alguna manera me gustan estos programas "más cortos" que muestran un problema (¿fundamental?). Al probar un poco de código de plantilla en VS2008 este error apareció (que también ha sido confirmado para VS2010 y VS2012, ver más abajo):Error de compilador VS C2752 ("más de una especialización parcial coincide con") en STL

c: \ archivos de programa (x86) \ Microsoft Visual Studio 9.0 \ VC \ include \ xmemory (225): error C2752: 'std :: _ Ptr_cat_helper < _T1, _t2>': más de una especialización parcial coincide con la lista de argumentos de plantilla

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

podría reducirse el problema de las tres líneas siguientes :

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

cuenta que la siguiente es todo muy bien

#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; 

Traté de arreglar xutility suministrando spezializations plantilla adicionales para _Ptr_cat_helper estructura - sin suerte. ¿Alguna idea de lo que sale mal? ¿O cómo trabajar sin perder el const?

+1

¿No tienes un VS instalar delante de mí, pero funciona con GCC. Es posible que haya encontrado un error en su lib estándar. –

+0

Actualmente no es posible la actualización VS: dependemos de dlls (usando componentes MFC) de otros grupos ... Pero sería genial escuchar si las tres líneas anteriores compilan en VS2010 – coproc

+0

Disculpe, no compila, por eso eliminado ese comentario. :/No está del todo claro cuál debería ser el elemento del vector, sin embargo. ¿Un puntero a una matriz de tres elementos de flotadores const? – Xeo

Respuesta

8

El problema es de hecho una ambigüedad en una especialización parcial:

Internamente, el asignador utiliza algunos metaprogramming (_Ptr_cat) para determinar si el DTOR es para ser llamado en los elementos del vector (o no hacer nada). Esta metaprogramación intenta diferenciar algunos casos mediante el uso de la especialización parcial. _Ptr_cat usa _Ptr_cat_helper que se está especializando en el tipo de puntero del asignador del vector; el vector value_type es TPointer const* == const float (*)[3], por lo que el asignador del vector tiene un tipo de puntero const float(**)[3].

Cuando se utiliza std::vector < const float(*)[3] >, el mensaje de error contiene la parte [3], mientras que usando std::vector < TPoint const* >, la [3] no se muestra O.o

_Ptr_cat espera dos argumentos de plantilla del mismo tipo con diferente posiblemente c-calificador, por ejemplo float*, float const*. Ahora, los dos tipos de entrada son ambos const float (**)[3]. MSVC resuelve ambiguamente las especializaciones de _Ptr_cat_helper: Ty**, Ty const** y/o Ty**, Ty**. Lo verifiqué al escribir un pequeño ejemplo que imita la especialización parcial de _Ptr_cat_helper (solo plantillas simples, sin Std Lib involucrado).

Sin embargo, no puedo explicar por qué sucede esto. Curiosamente, no hay ambigüedad cuando se configura un ejemplo utilizando solo un parámetro de especialización: const float(**)[3] se resuelve en Ty const** con Ty = float const[3] como se esperaba.

Gracias a Peter Alexander, también probé mi ejemplo simple (2 parámetros de plantilla) con g ++, y funcionó como se esperaba, sin ambigüedad. Tal vez esto podría ser un problema de compilación?

Permítanme proponer algunas soluciones:

  • Si realmente desea modificar la norma lib MSVC, se podría añadir una especialización _Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] > que se ajusta exactamente y resuelve la ambigüedad. Lamentablemente, debe proporcionar la dimensión explícitamente (3).
  • No utilice las matrices aquí. Utilice std::array (disponible en tr1 en VS08) o estructuras o punteros planos (float const* en lugar de float const[3])
  • utilizar un contenedor simple:

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

    funciona bien para mí.

Editar: aquí está el ejemplo he utilizado:

#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

'Tal vez esto podría ser un problema para el compilador' - entonces esperaría que fuera un problema de la biblioteca. Todavía +1 para el análisis – sehe

+0

Como el pequeño ejemplo que escribí compila bien con g ++ y no con MSVC, concluyo que esto no es problema de la biblioteca principalmente. Ya he encontrado algunos errores de compilador (confirmados), y sé que estos son realmente raros, por lo tanto, intento formularlos de forma conservadora. – dyp

+1

¿Huh? Las implementaciones de la biblioteca son totalmente diferentes ... No digo que no pueda ser un problema de compilación, sino hasta que, por ejemplo, muestre GCC + STLPort compila esto, mientras que MSVC + STLPort aún no tiene bases pequeñas – sehe

Cuestiones relacionadas