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函数模板实例化,我也想避免这种情况。我想交一个朋友,但不是一个朋友,如果和不一样。同时,我也想提供类内部的定义。是否可以?friendBasef<T>Base<T>f<U>Base<T>UT

4

2 回答 2

5

你真的需要f在类中定义吗?如果你在外面定义它,你的问题就消失了,你也可以强制执行你想要的一对一关系(即只是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; 
};

但是,请注意,only f<T>is afriend ofBase<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>两次(在任何上下文中)时,您提供了f. 请注意,这f不依赖于,也不能使用; 对所有人来说都是相同的功能。TTBase<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 回答