4

このコード:

template <typename T>
struct A
{
     T t;

     void DoSomething()
     {
          t.SomeFunction();
     }
};

struct B
{
};

A<B> a;

を呼び出さない限り、問題なく簡単にコンパイルできますa.DoSomething()

However, if I define DoSomething as a virtual function, I will get a compile error saying that B doesn't declare SomeFunction. I can somewhat see why it happens (DoSomething should now have an entry in the vtable), but I can't help feeling that it's not really obligated. Plus it sucks.

Is there any way to overcome this?

EDIT 2: Okay. I hope this time it makes sence: Let's say I am doing intrusive ref count, so all entities must inherit from base class Object. How can I suuport primitive types too? I can define:

template <typename T>
class Primitive : public Object
{
    T value;
public:
    Primitive(const T &value=T());

    operator T() const;

    Primitive<T> &operator =(const T &value);
    Primitive<T> &operator +=(const T &value);
    Primitive<T> &operator %=(const T &value);

    // And so on...
};

を使うことができます...しかし、どうPrimitive<int>ですか?フロートには演算子がないため、問題のようです。しかし、実際にはそうではありません。これは、テンプレートの意図的な機能の 1 つです。Primitive<char>Primitive<float>%=operator %=Primitive<float>

何らかの理由で、operator %=仮想と定義する場合。Primitive<float>または、リンク エラーを回避するために dll から事前にエクスポートする場合operator %=Primitive<float>. operator %=inPrimitive<float>の vtableにダミーの値を入力するだけであれば(例外が発生しますか?)、すべて問題ありませんでした。

4

4 に答える 4

2

仮想を選択可能な基本クラスに入れます...

struct Jumper
{
    virtual void Jump =0;
};

struct Crawler
{
    virtual void Crawl() =0;
};

struct JumperCrawler:
    public Jumper,
    public Crawler
{
};

template<typename T, typename Methods>
class ICanBoostJumpingAndCrawling :
    public Methods
{
    T t;
};

メソッド テンプレート パラメーターとして指定された Jumper、Crawler、または JumperCrawler で ICanBoostJumpingAndCrawling を使用できるようになりました。サブクラスでジャンプやクロールを実装できるように、そこから派生する必要があることを認識しています。

参考までに、これにより、「ICanBoostJumpingAndCrawling」という名前が完全に誤解を招く可能性があります。それができる場合とできない場合があるためです。つまり、「ブースター」などの名前に変更する必要があります。

于 2009-09-28T23:52:15.967 に答える
0

したがって、コンパイラは、使用中のものだけをコンパイル単位内で処理できる必要があります。複数のコンパイル ユニットを使用し始めるとすぐに、スコープが制限されなくなり、すべてのクラスが確実にコンパイルできるようにするために必要な手順が実行されます。

ライブラリからのエクスポートでは事前エクスポートを強制しないため、すべてのコードを同じコンパイラでコンパイルする限り、テンプレートをエクスポートしないという警告を無視できます。テンプレートはすべての場所で同じようにコンパイルされ、必要なものだけをコンパイルします。各コンパイル単位内で必要です。

仮想の問題を回避するには、問題を他のクラスに任せることが最善の方法です。テンプレートに仮想を入れないでください。

多分

  • テンプレートに「特性」部分を追加すると、安価な方法が可能になります。
  • シムを使用するように、多重継承を使用して複合テンプレートを定義します

すなわち。

template <typename T>
class Additive
{
public:
    Primitive<T> &operator =(const T &value);
    Primitive<T> &operator +=(const T &value);
};

template <typename T>
class Multiplicative
{
public:
    Primitive<T> &operator *=(const T &value);
    Primitive<T> &operator /=(const T &value);
};

template <typename T>
class Integers : public Additive<T>, public Multiplicative<T>;

私は本当に戻って、テンプレートを作成するための適切なレベルの情報を抽象化しているかどうかを尋ねます.

于 2009-09-29T02:12:39.763 に答える
0

これはバグではなく、機能です -- 真剣に。一度に、ほとんどのコンパイラはコードをコンパイルしませんでした。まさにあなたが与えた理由です。それ以来、標準で必要とされていることもあり、コンパイルするように更新されました。

C++ 0x 標準にはかなり長い間 "Concepts" と呼ばれる機能があり、T が戻り値の型、引数の型などを含む 'SomeFunction' という名前のメンバーを必要としていることを指定できました。

悲しいことに、標準委員会の最後の会議で、概念を完成させると、ほとんどの人が待ちたがる標準をより長く遅らせることが決定されたため、概念を削除しました。

それほど良くはありませんが、Boost には、あなたが求めていることを実行できるコンセプト チェックライブラリがあります。

于 2009-09-28T23:20:45.243 に答える
0

これを克服する 1 つの方法は、テンプレート引数 B に対して A を特化し、DoSomething() を宣言しないことです。

template <>
struct A<struct B>
{
     T t;

};

もちろん、これは A 構造体全体を最初から実装する必要があることを意味します。

于 2009-09-28T23:22:37.707 に答える