6

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

c:\program files (x86)\microsoft visual studio 9.0\vc\include\xmemory(225) : error 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

注意以下都可以

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

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

4

1 回答 1

8

这个问题确实是部分专业化的模棱两可:

在内部,分配器使用一些元编程(_Ptr_cat)来确定是否要在向量的元素上调用 dtor(或什么都不做)。这种元编程试图通过使用部分特化来区分某些情况。_Ptr_cat使用_Ptr_cat_helperwhich 专门用于向量的分配器的指针类型 - 向量的value_typeis TPointer const* == const float (*)[3],因此向量的分配器具有指针类型const float(**)[3]

使用std::vector < const float(*)[3] >时,错误消息包含[3]部分,而使用std::vector < TPoint const* >时,[3]不显示 oO

_Ptr_cat期望两个相同类型的模板参数,可能具有不同的 c 限定符,例如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**with 。Ty = float const[3]

感谢 Peter Alexander,我还用 g++ 尝试了我的简单示例(2 个模板参数),它按预期工作,没有歧义。也许这可能是编译器问题?

让我提出一些解决方法:

  • 如果您真的想修改 MSVC 标准库,您可以添加一个_Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] >完全适合并解决歧义的专业化。不幸的是,您必须明确提供维度 (3)。
  • 不要在这里使用数组。使用std::arraytr1在 VS08 中可用)或结构或普通指针(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();
}
于 2012-10-06T21:36:24.753 回答