4

テンプレート化されたパラメーターを使用して、非テンプレートクラスのテンプレートメンバー関数を特殊化しようとしています。

#include <array>
class C
{
public:
  template<class Container>
  void Foo( Container& )
  {
    // ...
  }
};

template<class T, std::size_t N>
template<>
void C::Foo< std::tr1::array<T,N> >( std::tr1::array<T,N>& )
{
  // special
}

これで「明示的なテンプレート引数の不正使用」というエラーが発生します。これを有効にするための正しい構文は何ですか?


更新

おそらく、私は過度に単純化することによって問題を混乱させました。私が本当にやりたいのは、扶養家族の名前が関係しているこの1つのケースを特別に処理することです。これは、ここの作品にモンキーレンチを投げ込んでいる可能性があると思います。私の当初の考えは、関数自体をオーバーロードすることでした。

class C
{
public:
  template<class Iter>
  void Foo( Iter )
  {
    std::cout << "Normal\n";
  }

  template<class T, std::size_t N>
  void Foo( typename std::tr1::array<T,N>::iterator )
  {
    std::cout << "Special\n";
  }
};

int main()
{
  C c;
  std::tr1::array<int,10> a1;
  c.Foo( a1.begin() ); // Doesn't print "Special"!
}

しかし、特別なFooは呼び出されません。どうやってやるの?

4

2 に答える 2

2

メンバー関数のみがテンプレート化されます。つまり、template<...>そこでは1つだけを使用する必要があります。ただし、関数を部分的に特殊化することはできないため、それでも解決されません。

問題を処理する通常の方法は、特殊化ではなく、オーバーロードを使用することです(テンプレート関数の特殊化はそれほど有用ではありません)。

struct test {
   template <typename Container>
   void f( Container& ) { ... }

   template <typename T, int N>
   void f( std::array<T,N>& ) { ... }
};

違いは、これらが(特殊化ではなく)2つの別個のテンプレート関数であることに注意してください。

編集:更新後

質問を更新すると、問題が完全に変わります。あなたが見ている問題は、2番目のバージョンの引数が従属名であり、それ自体が推論できないということです。関数呼び出しが与えられると、コンパイラーはどのタイプTを判別できず、積分定数Nはその特定のインスタンス化に一致します。別の例を考えてみましょう。

template <typename T>
struct inner_int {
   typedef int type;
};
template <typename T>
void foo( typename inner_int<T>::type ) {
}
int main() {
   foo( inner_int<double>::type() );
}

コンパイラは、呼び出しを処理するときにmain、テンプレートをインスタンス化して型を抽出し、そこから一時的なものを作成して、処理方法を決定しようとしますが、その時点では、右辺値fooで呼び出されていることしかわかりません。 int..オリジナルinner<double>::typeはなくなりましたが、今では正しくfoo( int() )、コンパイラはすべての可能なタイプを使用してインスタンス化を試み、inner_intそれらのいずれかが適合するかどうかを判断する必要があります。最悪の場合、上記のように、多くが一致します。

于 2011-05-20T19:58:01.690 に答える
1

部分関数テンプレートの特殊化は違法です。C ++ 03標準から、§14/ 2:

テンプレート宣言は、名前空間スコープまたはクラススコープ宣言としてのみ表示できます。関数テンプレート宣言では、declarator-idtemplate-name (つまり、template-idではない)でなければなりません。[注:クラステンプレート宣言で、クラス名がtemplate-idの場合、宣言はクラステンプレートの部分的な特殊化を宣言します。]

代わりに、関数を単純にオーバーロードする必要があります。

class C
{
public:
    template<typename Container>
    void Foo(Container&)
    {
        // ...
    }

    template<typename T, std::size_t N>
    void Foo(std::tr1::array<T, N>&)
    {
        // special
    }
};

編集(OPの編集に応じて):

この特定のシナリオの回避策のみを探している場合は、std(::tr1)::array<T,N>::iteratorが単純T*であるため、「特別な」過負荷は次のようになります。

template<typename T>
void Foo(T*&)
{
    // special
}
于 2011-05-20T20:00:38.480 に答える