在类内定义友元函数模板时如何避免重定义错误?

发布于 2025-01-06 17:07:01 字数 1325 浏览 1 评论 0原文

考虑这段代码:

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 函数模板的所有实例化为 Base 类模板的所有实例化的 friend ,我也想避免。我想让 f 成为 Base 的好友,但不让 f 成为 Base的好友。如果 UT 不相同,则 T>。同时我也想提供类内部的定义。是否可以?

Consider this code:

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() {}
};
*/

It compiles fine now (ideone). But if I uncomment the definition of B, then it gives the following error (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

I know (well,I think I know) the reason why it gives this error.

So my question is :

How to avoid redefinition error in case of in-class definition of friend function template?

As long as I provide the definition of the primary template (not specialization) inside the class, I will get this error. There is also another problem with defining primary template in this way: it makes all instantiations of f function template friend of all instantiations of Base class template, which I also would like to avoid. I want to make f<T> a friend of Base<T> but not f<U> a friend of Base<T> if U and T are not same. At the same time, I also want to provide the definition inside the class. Is it possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

灵芸 2025-01-13 17:07:01

您真的需要在类中定义 f 吗?如果您在外部定义它,您的问题就会消失,并且您还可以强制执行您想要的一对一关系(即只有 fBase的友元。 code>):

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; 
};

但是,请注意,只有 fBase 的友元这一事实不会阻止以下代码的编译:

B b;
f<A>(&b); // compiles, f<A> calls Base<A>::run, but the cast is wrong

Do you really need to define f into the class? If you define it outside, your problem disappears and you can also enforce the one-to-one relationship you want (i.e. only f<T> is a friend of 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; 
};

However, note that the fact that only f<T> is a friend of Base<T> will not prevent the following code from compiling:

B b;
f<A>(&b); // compiles, f<A> calls Base<A>::run, but the cast is wrong
月下客 2025-01-13 17:07:01

友元函数是一个全局函数,即使您将其实现放入任何类的主体中也是如此。问题是,当您实例化 Base 两次(在任何上下文中)时,您提供了 f 的两个实现。请注意,f依赖于T,并且它不能使用T;对于所有 Base 来说,它的功能都是相同的。

一个简单的解决方案是仅在类模板内提供 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++ 进行编译

A friend function is a global function, even if you put its implementation into the body of any class. The problem is that when you instantiate Base<T> twice (in any context) you provide two implementations of f. Note, that f does not depend on T, and it cannot use T; it's the same function for all Base<T>.

A simple solution is to provide only the declaration of f within the class template and implementation outside it:

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() {
}

The above code compiles with my g++

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文