web-dev-qa-db-ja.com

名前空間以外のスコープでの明示的な特殊化

template<typename T>
class CConstraint
{
public:
    CConstraint()
    {
    }

    virtual ~CConstraint()
    {
    }

    template <typename TL>
    void Verify(int position, int constraints[])
    {       
    }

    template <>
    void Verify<int>(int, int[])
    {   
    }
};

これをg ++でコンパイルすると、次のエラーが発生します。

名前空間以外のスコープ 'class CConstraint'での明示的な特殊化

VCでは、問題なくコンパイルされます。誰でも回避策を教えてもらえますか?

120
Mark

この場合、VC++は非準拠です。明示的な特殊化は、名前空間のスコープ内になければなりません。 C++ 03、§14.7.3/ 2

明示的な特殊化は、テンプレートがメンバーである名前空間で宣言されるか、メンバーテンプレートの場合、包含クラスまたは包含クラステンプレートがメンバーである名前空間で宣言されます。
メンバー関数、メンバークラス、またはクラステンプレートの静的データメンバーの明示的な特殊化は、クラステンプレートがメンバーである名前空間で宣言されます。

さらに、C++ 03、§14.7.3/により、含まれるクラスを明示的に特化せずにメンバー関数を特化できないという問題があるため、1つの解決策はVerify()特殊化された、おそらく無料の関数に転送します。

namespace detail {
    template <typename TL> void Verify     (int, int[]) {}
    template <>            void Verify<int>(int, int[]) {}
}

template<typename T> class CConstraint {
    // ...
    template <typename TL> void Verify(int position, int constraints[]) {
        detail::Verify<TL>(position, constraints);
    }
};
92
Georg Fritzsche

それを解決する別の方法は、プライベート関数に委任し、その関数をオーバーロードすることです。この方法では、*thisのメンバーデータと外部テンプレートパラメータータイプに引き続きアクセスできます。

template<typename T>
struct identity { typedef T type; };

template<typename T>
class CConstraint
{
public:

  template <typename TL>
  void Verify(int position, int constraints[])
  {
    Verify(position, constraints, identity<TL>());
  }

private:
  template<typename TL>
  void Verify(int, int[], identity<TL>)
  {

  }

  void Verify(int, int[], identity<int>)
  {

  }
};

クラス宣言の外でテンプレートの特殊化を行ってください。 gccはインラインテンプレートの特殊化を許可しません。

別のオプションとして、行テンプレート<>を削除するだけでうまくいくようです。

12
bop

さらに良いことには、部分的な特殊化とデフォルトのテンプレート引数を組み合わせることができます。このようにVC++コードを変更することはわずかです。これは、特殊な関数の呼び出しを変更する必要がないためです。

template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}

template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}
4
vitke

メンバーテンプレートを明示的に特殊化できない場合がありますが、部分的に特殊化できます。 2番目のパラメーター「int dummyParam」を追加し、それを特殊化に追加する場合、両方のコンパイラーで機能するはずです。

私はこれを10秒以上前に知っていたわけではありませんが、同じエラーでグーグルで このリンク に遭遇し、メンバーテンプレートの専門化に役立ちました。

1
M. Tibbits