【问题标题】:defining friend function within templated class在模板类中定义友元函数
【发布时间】:2011-05-16 05:02:00
【问题描述】:

我使用三个不同的文件来定义一个模板类。类声明在.h 文件中,实现在.cpp 文件中,显式实例包含在.inc 文件中。 我正在尝试定义一个朋友函数,它能够访问模板类的私有数据成员。 与模板类的情况一样,函数将在 3 个单独的文件中定义、实现和实例化。 当我尝试调用该函数时,我收到以下错误消息:

myclass.h:error: ‘doSomething’ is neither function nor member function; cannot be declared friend

myclass.h:error: expected ‘;’ before ‘<’ token

mymethod.h: error: ‘friend’ used outside of class

有人对如何解决这个问题有任何建议吗?我试图简化下面的代码。

myclass.h

  template<class T>
  class MyClass{

      friend T doSomething<T>( MyClass<T> *, T, int);
      friend  MyClass<T> * doSomethingElse<T>( const MyClass<T> *, const MyClass<T> *);
      public:
               ...
      private:
         T *m_pMyMatrix;
  };

mymethod.h

#include <myclass.h>
template <class T> friend T doSomething( MyClass<T> *, T, int);
template <class T> MyClass<T>* doSomethingElse(const MyClass<T>*, const MyClass<T>*);

mymethod.cpp

#include <mymethod.h>
template <class T>
T doSomething( MyClass<T> * pData, T val, int index){
   // the actual code does sth. more complex than the code below.
   pData->m_pMyMatrix[index]+=val;
   return pData->m_pMyMatrix[index];
}

template <class T>
MyClass<T>* doSomethingElse(const MyClass<T> * pData1, const MyClass<T> * pData2){
   ...
   T res1 = doSomething(pData1, val1, index1);
   ...
}
#include "mymethod-impl.inc"

mymethod-impl.inc

template float doSomething( MyClass<float> *, float, int);
template double doSomething( MyClass<double> *, double, int);

template MyClass<float>* doSomethingElse(const MyClass<float>*, const MyClass<float>*);
template MyClass<double>* doSomethingElse(const MyClass<double>*, const MyClass<double> *);

【问题讨论】:

  • 使用好友功能可能很危险!任何人都可以编写具有相同签名的静态函数并获得对您的类的控制权,除非您的朋友函数使用命名空间声明。
  • @Edwin:我想这属于旧的“防止墨菲家伙获得控制权,反正反对马基雅维利是徒劳的”。
  • @sbi:我只是在说明当您使用朋友功能时(您致力于一个已知的可信实体),请确保您的朋友确实是您想要的。猜你想要什么。

标签: c++ templates friend


【解决方案1】:

我认为这应该可行

template<class T>
class MyClass;

template <class T>
T doSomething( const MyClass<T> *, T, int);

template<class T>
class MyClass {
  friend T doSomething<T>( const MyClass<T> *, T, int);
public:
  ...
private:
  T *m_pMyMatrix;
};

也就是说,您需要先声明模板,然后才能使其(或其实例)成为朋友。

【讨论】:

  • @Javier:现在试试,我已经更正了代码(模板函数声明中不应使用friend关键字)。
  • @David:谢谢。我没有仔细看就复制了声明。
  • @Javier:在将函数模板声明为friend 之前,您将无法绕过声明(并且您必须声明类模板才能成为能够声明函数模板)。但是,您可以稍后定义该模板。 friend 的所有编译器需要的是函数模板的声明(而所有编译器需要的是类模板的声明)。
  • 如果我的doSomething 朋友函数现在有一个Foo&lt;S&gt; 类型的新参数,我该怎么办?我应该在两个类定义中将doSomething&lt;S,T&gt; 定义为朋友吗(对于MyClass 和Foo 类)?
  • @Javier:我看到 Simone 已经在帮助你了。到目前为止,我完全同意他写的所有内容,如果我重复它会变得毫无意义。
【解决方案2】:

我想我解决了这个问题:

mymethod.h

template<class T> class MyClass;

template<class T> 
T doSomething<T>(const MyClass<T>* pData, T val, int index);

myclass.h

#include "mymethod.h"

template<class T>
class MyClass {
    friend T doSomething<T>(const MyClass<T>* pData, T val, int index);

public:
    // ...

private:
    T *m_pMyMatrix;
};

mymethod.cpp

#include "myclass.h"

template<class T>
T doSomething(const MyClass<T>* pData, T val, int index)
{
    pData->m_pMyMatrix[index]+=val;
    return pData->m_pMyMatrix[index];
}

template<> float doSomething( const MyClass<float> *, float, int);
template<> double doSomething( const MyClass<double> *, double, int);

实际上,您只需在 MyClass 定义之前声明模板函数。

【讨论】:

  • 您需要在类定义之前将 mymethod.h 包含在 myclass.h 中(并删除类外的 friend 声明MyClass 的定义)。
  • @Javier:你不需要函数定义,只需要声明。基本上在定义MyClass 之前,您必须转发声明MyClass 模板,然后声明doSomething 模板函数。实际的实现可以放在任何地方。一般来说,如果模板在单个头文件中提供,生活会容易得多,但在某些情况下有理由不这样做(编译时间,修复可用作模板实例化的类型 - 即未能实例化其他类型的模板...)
  • 我认为你不能与未声明的函数模板成为朋友。
  • 在 g++ 3.4.5 中编译。此外,它是一个未定义的函数,不是未声明的。
  • 附带说明,我会将两个头文件合并为一个头文件。模板类和模板函数是如此耦合的,将它们分开是没有意义的。
猜你喜欢
  • 2016-06-23
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-19
  • 1970-01-01
  • 2011-07-15
相关资源
最近更新 更多