Somehow I like these "shortest" programs showing a (fundamental?) problem. When testing some template code in VS2008 this error showed up (it has also been confirmed for VS2010 and VS2012, see below):
c:\program files (x86)\microsoft visual studio 9.0\vc\include\xmemory(225) : error C2752: 'std::_Ptr_cat_helper<_T1,_T2>' : more than one partial specialization matches the template argument list
with [ _T1=const float (**), _T2=const float (**) ]
I could boil down the problem to the following three lines:
#include <vector>
typedef float TPoint[3];
std::vector<TPoint const*> points; // error C2752
Note that the following is all 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;
I tried to fix xutility by supplying additional template spezializations for struct _Ptr_cat_helper - without luck. Any ideas what goes wrong? Or how to work around without loosing the const
?
The problem is indeed an ambiguity in a partial specialization:
Internally, the allocator uses some metaprogramming (_Ptr_cat
) to determine if the dtor is to be called on the elements of the vector (or do nothing). This metaprogramming tries to differentiate some cases by using partial specialization. _Ptr_cat
uses _Ptr_cat_helper
which is being specialized on the vector's allocator's pointer type -- the vector's value_type
is TPointer const* == const float (*)[3]
, so the allocator of the vector has a pointer type const float(**)[3]
.
When you use std::vector < const float(*)[3] >
, the error message contains the [3]
part, whereas using std::vector < TPoint const* >
, the [3]
is not displayed o.O
_Ptr_cat
expects two template arguments of the same type with possibly different c-qualifier, e.g. float*, float const*
.
Now, the two input types are both const float (**)[3]
. MSVC resolves them ambiguously to the specializations of _Ptr_cat_helper
: Ty**, Ty const**
and/or Ty**, Ty**
. I verified that by writing a small example which mimics the partial specialization of _Ptr_cat_helper
(just plain templates, no Std Lib involved).
Yet, I cannot explain why this happens. Strangely, there's no ambiguity when setting up an example using only one specialization parameter -- const float(**)[3]
is resolved to Ty const**
with Ty = float const[3]
as expected.
Thanks to Peter Alexander, I also tried my simple example (2 template parameters) with g++, and it worked as expected, no ambiguity. Maybe this might be a compiler issue?
Let me propose some workarounds:
_Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] >
which fits exactly and resolves the ambiguity. Unfortunately, you have to provide the dimension explicitly (3).std::array
(available in tr1
in VS08) or structures or plain pointers (float const*
instead of float const[3]
)Use a simple wrapper:
template < typename T > struct wrapper { T wrapped; }
std::vector < wrapper < TPoint > const* > m;
works fine for me.
Edit: here's the example I used:
#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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With