6

どういうわけか、(根本的な?)問題を示すこれらの「最短」プログラムが好きです。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 (**)
   ]

問題を次の 3 行に要約できます。

#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_helper、ベクトルのアロケータのポインタ型に特化されているものを使用します。ベクトルvalue_typeは isTPointer const* == const float (*)[3]であるため、ベクトルのアロケータはポインタ型を持ちますconst float(**)[3]

を使用するstd::vector < const float(*)[3] >とエラーメッセージに の[3]部分が含まれるのに対し、 を使用std::vector < TPoint const* >する[3]と表示されない oO

_Ptr_catは、c 修飾子が異なる可能性のある同じ型の 2 つのテンプレート引数を想定していますfloat*, float const*。現在、2 つの入力タイプは bothconst float (**)[3]です。MSVC は、それらをあいまいに_Ptr_cat_helper:Ty**, Ty const**および/またはの特殊化に解決しますTy**, Ty**。の部分的な特殊化を模倣する小さな例を書くことで、それを確認しました_Ptr_cat_helper(単純なテンプレートで、標準ライブラリは含まれていません)。

しかし、なぜこのようなことが起こるのか、私には説明できません。奇妙なことに、特殊化パラメーターを 1 つだけ使用して例を設定する場合、あいまいさはありません。期待どおりconst float(**)[3]に解決さTy const**Ty = float const[3]ます。

Peter Alexander のおかげで、私の簡単な例 (2 つのテンプレート パラメーター) を g++ で試してみたところ、期待どおりに動作し、あいまいさはありませんでした。多分これはコンパイラの問題でしょうか?

いくつかの回避策を提案させてください。

  • MSVC 標準ライブラリを本当に変更したい場合は、_Ptr_cat_helper < const Ty (**)[3], const Ty (**)[3] >正確に適合し、あいまいさを解決する特殊化を追加できます。残念ながら、ディメンションを明示的に指定する必要があります (3)。
  • ここでは配列を使用しないでください。std::array( tr1VS08 で利用可能) または構造体またはプレーン ポインター (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 に答える