STL中的VS编译器错误C2752("多个部分特化匹配")

cop*_*roc 6 c++ stl visual-c++

不知怎的,我喜欢这些"最短"的程序,显示出(基本的?)问题.在VS2008中测试一些模板代码时出现此错误(VS2010和VS2012也已确认,见下文):

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 (**)
   ]
Run Code Online (Sandbox Code Playgroud)

我可以将问题归结为以下三行:

#include <vector>
typedef float TPoint[3];
std::vector<TPoint const*> points; // error C2752
Run Code Online (Sandbox Code Playgroud)

请注意,以下都可以

#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;
Run Code Online (Sandbox Code Playgroud)

我试图通过为struct _Ptr_cat_helper提供额外的模板特性来修复xutility - 没有运气.任何想法出了什么问题?或者如何在不失去的情况下解决const

dyp*_*dyp 8

问题确实是部分专业化的含糊不清:

在内部,分配器使用一些元编程(_Ptr_cat)来确定是否要在向量的元素上调用dtor(或什么都不做).这种元编程试图通过使用部分特化来区分某些情况._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]不显示oO

_Ptr_cat期望两个相同类型的模板参数可能具有不同的c-qualifier,例如float*, float const*.现在,两种输入类型都是const float (**)[3].MSVC模糊地解析它们的专业化_Ptr_cat_helper:Ty**, Ty const**和/或Ty**, Ty**.我通过编写一个模仿部分特化的小例子来证实_Ptr_cat_helper(只是简单的模板,没有涉及Std Lib).

然而,我无法解释为什么会发生这种情况.奇怪的是,有设置只使用一个专门的参数,例如,当没有歧义- const float(**)[3]被解析为Ty const**Ty = float const[3]预期.

感谢彼得亚历山大,我也用g ++尝试了我的简单示例(2个模板参数),它按预期工作,没有歧义.也许这可能是一个编译器问题?

让我提出一些解决方法:

  • 如果您真的想要修改MSVC标准库,您可以添加一个_Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] >完全适合的特殊化并解决歧义.不幸的是,您必须明确提供维度(3).
  • 不要在这里使用数组.使用std::array(tr1在VS08中可用)或结构或普通指针(float const*而不是float const[3])
  • 使用简单的包装器:

    template < typename T > struct wrapper { T wrapped; }
    std::vector < wrapper < TPoint > const* > m;
    
    Run Code Online (Sandbox Code Playgroud)

    对我来说很好.

编辑:这是我用过的例子:

#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();
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,重现错误不需要两个间接级别.一个简单的指针到数组类型可以证明这个问题.我用于错误报告的最小repro如下:https://gist.github.com/3847212.我建议在这里使用`array <T,N>`作为一种解决方法(实际上,我建议使用`array <T,N>`你现在使用的任何地方`T [N]`:真的没有使用普通数组的原因,除非你需要这样做才能与C代码互操作). (2认同)