3

テンプレートクラスがあります:

template<typename T>
class A {
public:
 virtual void func(T t);
 virtual void func2(T t);
 .
 .
 .
 virtual void funcN(T t);
}

基本的に多くのクラスはフォームAを継承しますが、Tは常に2つのタイプBまたはCのいずれかです。

現在、クラスで行うすべての変更により、非常に長いビルドが発生します。

TはBまたはCのいずれかである可能性があるため、クラスを通常のクラスに変換したいと思います。

各関数を2回コピーせずに、この変更をスマートでクリーンな方法で行う方法はありますか?

ありがとう

4

4 に答える 4

7

最も簡単な解決策は、おそらく明示的な特殊化を使用することです。テンプレートは保持しますが、インスタンス化するクラスをコンパイラーに明示的に指示します。

class Aクラスとそのメンバーの宣言のみを含むようにヘッダーファイルを変更します(通常のクラスの場合と同様)。次にA.cpp、のメンバー関数の実装とA明示的な特殊化を含むファイルを次のように作成します

#include <A.h>
#include <B.h>
#include <C.h>

//... Implementation of A

template class A<B>; // explicit instantiation for B
template class A<C>; // and for C

このファイルをプロジェクトに追加します。

于 2012-12-26T16:28:30.417 に答える
2

プリプロセッサを使用してテンプレートになるクラスの共有部分を定義するなどのハックに頼らなければ、コードの重複を導入せずにテンプレートを回避することはできません。

Bとが共通の祖先を共有していない場合は、次のように、とCの非テンプレートクラスを導入A<B>A<C>、それらから継承できます。

class AofB : public A<B> {};

class AofC : public A<C> {};

class SomeClass1 : public AofB { // this used to be A<B>
    ...
};

class SomeClass2 : public AofC { // this used to be A<C>
    ...
};

ただし、これによってコンパイルの速度が変わる可能性はほとんどありません。

Bとが多くの共通機能を共有している場合は、の共通の祖先を多形的に使用する非Cテンプレートバージョンを作成することを検討してください。ただし、これは必ずしも望ましいとは限りません。これは、以前はテンプレート引数のインスタンスで十分だった場所でポインタ/参照を使用する必要があるためです。ABCT

于 2012-12-26T16:19:48.350 に答える
1

1つの可能性は、共通の基本クラスを持っBC派生し、Aその基本クラスへのポインターまたは参照を操作することです。

class base {};
class B : public base {};
class C : public base {};

class A {
public:
    virtual void func(base &b);
    virtual void func2(base &b);
    // ...
    virtual void funcN(base &b);
};

これにより、Aの変更によるBとCの再コンパイル回避されますが、実行時に追加のコストが発生します。具体的には、Aはポインタまたは参照を介してBおよびCオブジェクトと連携する必要があり、これにはある程度のオーバーヘッドが伴います。

于 2012-12-26T16:20:42.990 に答える
1

私がこの権利を読んでいる場合、あなたの本当の質問は、「このクラスのテンプレートを解除するにはどうすればよいか」ではなく、「このテンプレートクラスを使用するときにビルド時間を短縮するにはどうすればよいですか」です。

ほとんどの場合、問題はテンプレートのインスタンス化ではなくすべてのファイルを再コンパイルする必要があることに起因しますが、それでも頭に浮かぶ最も明白な解決策は(仮想関数がA両方BCオブジェクトをパラメーターとして使用する場合)、コンパイル時からランタイムポリモーフィズム。

共通の基本クラスを導入し、Bテンプレート化する必要がなく、代わりにオブジェクトへのポインター/参照を受け入れるだけでC、共通のインターフェースを利用して必要な作業を行うことができます。これにより、コンパイル時間がすぐに短縮されますが、さらに節約が必要な場合は、pimplパターンを使用して、変更を使用するクライアントクラスから変更をさらに分離できます。ABC_Parent

いかなる場合でも、実際のインターフェースがA変更されたときに完全な再コンパイルを回避することはできません。

于 2012-12-26T20:30:24.560 に答える