4

私のクラスの1つは、テンプレート化された関数を宣言しています。

template<class A, class B>
A do_something(const std::vector<B> &data)

部分的に専門にしたいと思いtypename Aます。Bは非常に最小限のインターフェースを実装するタイプのファミリーであり、私たちはそれらを多く使用しているので、私の専門分野はで一般的なものにしたいと思いBます。typename Aリターンタイプとしてのみ使用されているため、これは二重に厄介だと思います。

インターネットから、関数を部分的に特殊化できないことを収集したので、次のようにクラスを作成しました。

template<class A, class B> 
class do_something_implementation {
  public:
    do_something_implementation(const std::vector<B> &data_) {
      data = data_;
    }

  int do_something_implementation<int, B>::operator()() {
    /* Complicated algorithm goes here... */
  }

  double do_something_implementation<double, B>::operator()() {
    /* Different complicated algorithm goes here... */
  }

  private:
      std::vector<B> data;
}

(Visual Studio 2008を使用して)それをコンパイルしようとすると、コンパイラがクラッシュし(!)、次のエラーが発生します。

fatal error C1001: An internal error has occurred in the compiler.

これは私の問題であり、コンパイラの問題ではないと思います。私が目指している部分的な特殊化を表現するためのより良い方法はありますか?

4

4 に答える 4

7

通常、次のようになります。

template <typename A, typename B>
struct DoSomethingHelper
{
    static A doIt(const std::vector<B> &data);
};

template <typename B>
struct DoSomethingHelper<double, B>
{
    static double doIt(const std::vector<B> &data) { ... }
};

template <typename B>
struct DoSomethingHelper<int, B>
{
    static int doIt(const std::vector<B> &data) { ... }
};

template<class A, class B>
A do_something(const std::vector<B> &data)
{ return DoSomethingHelper<A, B>::doIt(data); }
于 2010-12-14T14:31:59.797 に答える
4

静的メソッドへの古典的なフォワードを見てきましたが、特殊化するタイプが「完全」である場合、実際には別の方法があります。

関数を部分的に特殊化することはできないかもしれませんが、完全にオーバーロードすることはできます。

template <typename A, typename B>
A do(std::vector<B> const& data) { return this->doImpl(data, (A*)0); }

template <typename A, typename B>
A doImpl(std::vector<B> const& B, A*) { // generic implementation }

template <typename B>
int doImpl(std::vector<B> const& B, int*) { // int implementation }

template <typename B>
double doImpl(std::vector<B> const& B, double*) { // double implementation }

doImpl秘訣は、実際に適切な実装を選択することのみを目的として、「未使用」の引数をに渡すことです(オーバーロード解決のおかげで)。

ここでは、単純に渡すことを選択しまし(A*)0た。これは、のコンストラクターを含まないためですA(自明でない場合)。

このディスパッチイディオムは、STLで使用され、一部のイテレータカテゴリに対してより効率的なアルゴリズムを実装します(たとえば、std::distanceランダムイテレータの場合はO(1)です)。

静的メソッドと部分的な特殊化を備えたヘルパークラスを使用するよりもはるかに軽量だと思います...しかし、それは私だけかもしれません:)

于 2010-12-14T15:42:31.207 に答える
1

人々は通常、静的な実装に転送するだけです。

template<class A, class B> class X;
template<class A, class B> friend class X;
template<class A, class B> class X {
public:
    static A do_something(class_type* not_this, const std::vector<B>& data) {
        //...
    }
};
// partially specialize
template<class A, class B>
A do_something(const std::vector<B> &data) {
    return X<A, B>::do_something(this, data);
};
于 2010-12-14T14:31:53.307 に答える
1

あなたの問題の解決策ではありませんが(すでにいくつかあります)、あなたのコードで間違っていることのいくつか:

structテンプレートクラス宣言にorclassキーワードがありません。

template <typename A, typename B> struct do_something_implementation {
//                                ^^^^^^

クラス定義内では、クラスがテンプレートであるかどうかに関係なく、メンバー関数は修飾名を使用してはなりません。

class A {
   void A::foo() {} // Error, should be: void foo() {}
};

メンバーテンプレートの特殊化は、クラス定義内には表示できませんが、名前空間レベルで表示できます。

class B {
   template <typename T> void foo( T );
};
template <> void B::foo<int>( int ) {}
template <> void B::foo<double>( double ) {}

さらに、あなたの場合、メンバー関数はテンプレートではなく、テンプレート化されていないメンバー関数です(テンプレートは、関数自体ではなく、包含クラスです)。コードが効果的に実行しようとしているのは、一般的なテンプレート内で他のクラスのメンバー関数を定義することです。

全体として、コンパイラが実行しようとしていることを識別して適切なエラーメッセージを提供するのにコードの解析をほぼ不可能にするのに十分なエラーがありましたが、それでも、コピーした最初の行を指すエラーメッセージを提供する必要がありました。窒息死する。

于 2010-12-14T17:09:30.347 に答える