3

次のコードを検討してください。

template<typename T>
class Base
{
   template<typename U>
   friend void f(void *ptr) {
     static_cast<Base<U>*>(ptr)->run();
   }
   protected:
       virtual void run() = 0; 
};
 
class A : public Base<A>
{
   protected:
       virtual void run() {}
};
 
/*
class B : public Base<B>
{
   protected:
       virtual void run() {}
};
*/

現在は正常にコンパイルされています ( ideone )。しかし、 の定義のコメントを外すBと、次のエラー ( ideone )が発生します。

prog.cpp: In instantiation of ‘Base<B>’:
prog.cpp:20:   instantiated from here
prog.cpp:6: error: redefinition of ‘template<class U> void f(void*)’
prog.cpp:6: error: ‘template<class U> void f(void*)’ previously defined here

このエラーが発生する理由を知っています(まあ、知っていると思います)。

だから私の質問は:

フレンド関数テンプレートのクラス内定義の場合の再定義エラーを回避するには?

クラス内でプライマリ テンプレート(特殊化ではない)の定義を提供する限り、このエラーが発生します。この方法でプライマリ テンプレートを定義することには、別の問題もあります。クラス テンプレートのすべてのインスタンス化のf関数テンプレートfriendのすべてのインスタンス化をBase行うことです。これも避けたいと思います。ifとare not sameのf<T>友達になりたいのですBase<T>が、友達ではありません。同時に、クラス内での定義も提供したいと考えています。出来ますか?f<U>Base<T>UT

4

2 に答える 2

5

本当にfクラスに定義する必要がありますか? 外部で定義すると、問題が解消され、必要な 1 対 1 の関係を強制することもできます (つまり、f<T>は のフレンドのみですBase<T>)。

template <typename T> class Base;

template <typename U>
void f(void *ptr) {
   static_cast<Base<U>*>(ptr)->run();
}

template<typename T>
class Base
{
   friend void f<T>(void *ptr); //only one instanciation is a friend

   protected:
     virtual void run() = 0; 
};

ただし、 onlyf<T>が のフレンドであるという事実はBase<T>、次のコードのコンパイルを妨げないことに注意してください。

B b;
f<A>(&b); // compiles, f<A> calls Base<A>::run, but the cast is wrong
于 2012-02-17T10:40:24.007 に答える
1

フレンド関数は、その実装を任意のクラスの本体に配置した場合でも、グローバル関数です。問題は、Base<T>(任意のコンテキストで)2回インスタンス化すると、の2つの実装が提供されることですf。に依存f、 ;Tを使用できないことに注意してください。Tすべてので同じ関数ですBase<T>

f簡単な解決策は、クラステンプレート内の宣言とその外部の実装のみを提供することです。

template<typename T>
class Base
{
  template<typename U>
  friend void f(void *ptr);
  protected:
    virtual void run() = 0;
};


template<typename U>
void f(void *ptr) {
  static_cast<Base<U>*>(ptr)->run();
}

class A : public Base<A>
{
 protected:
   virtual void run() {}
};

class B : public Base<B>
{
protected:
  virtual void run() {}
};

int main() {
}

上記のコードは私のg++でコンパイルされます

于 2012-02-17T10:22:39.030 に答える