注意:这篇文章与这篇文章不同:Declare non-template friend function for template class outside the class,因此请先阅读我的问题,然后再将其标记为重复。
我想在类模板中声明一个非模板朋友函数,并且该朋友函数的参数和返回类型与模板参数不相关。我该怎么办?
请注意,它与之前的问题不同,因为在该问题中,该朋友函数的参数和返回类型与模板参数相关。
示例,从上面的问题改编而成:
// class.h
#include <iostream>
using namespace std;
template <typename T>
struct B
{
T value;
int value2;
B() : value2(1) {}
friend void modify(const int&); // unrelated to T!
void printValue2() {
modify(value2);
cout << value2 << endl;
}
};
// define friend function foo() in a class.cpp file, not in the header
void modify(const int &v) { v = v * 2 + 1; } // HOW should I write it?
// main.cpp
int main() {
B<int> b;
b.printValue2();
return 0;
}
我知道我可以在此模板类之外声明modify()
,以使其成为普通的普通函数。但我只希望该模板类可以访问modify()
。或者,为了实现访问控制的目标,我可以在此模板类中将modify()
定义为静态方法,但这将使该方法成为模板方法,迫使我在标头中对其进行定义。
后续行动:如果上述的朋友方法不起作用,我应该如何同时实现两个目标:
modify()
modify()
。接受的答案:
要实现上述两个目标,请不要滥用友谊。
最佳做法是让类模板私下继承非模板基类,并在该基类中声明与模板无关的常见非模板方法争论。
因此,您可以在单独的* .cpp文件中定义这些方法,从而减小标题的大小。
答案 0 :(得分:3)
您可以使用私有继承而不是友谊:
// class.h
#include <iostream>
class B_helper
{
protected:
static void modify(int &v);
};
template <typename T>
struct B : private B_helper
{
T value;
int value2;
B() : value2(1) {}
void printValue2() {
modify(value2);
std::cout << value2 << std::endl;
}
};
// class.cpp
void B_helper::modify(int &v) { v = v * 2 + 1; }
答案 1 :(得分:0)
您这样做:
// class.cpp
void modify(const int &v) { v = v * 2 + 1; }
您实际上是在滥用友谊,但是可以。这意味着您需要解决用friend
声明函数的含义:它只能通过ADL看到!现在没有没有方式来引用modify
,因为modify
不依赖B
,所以从不搜索B
的范围用于名为modify
的函数。
有一个解决方法,但这并不漂亮。您需要在使用它的每个函数中声明modify
。您也可以在全局范围内声明它,但是每个人都可以调用它。另外,您始终可以在detail
命名空间中声明它(但这有点相同的问题):
template<typename T>
void B<T>::printValue2() {
void modify(const int&);
modify(value2);
cout << value2 << endl;
}
答案 2 :(得分:0)
正如我在评论中所说,friend
ship控制着对一个类的访问。只要您的函数modify()
是独立函数,就不能成为朋友。您想从模板调用它时,也不能将其隐藏在.cpp文件中,但必须在类模板B及其成员使用modify()
的定义中可见。
一种解决方案是将modify
作为static
方法放入辅助非模板类中,该类又与模板B<>
成为朋友。
// file foo.h (header)
namespace foo {
template<typename> class B; // forward declaration
class exclusive_for_B
{
template<typename T>
friend class B<T>;
static void modify(int&x) // must take int&, not const int&
{ x &= x+42; }
};
template<typename T>
class B
{
int val;
public:
...
void printvalue()
{
exclusive_for_B::modify(val); // access via friendship
std::cout << val << '\n';
}
};
}