在模板类中声明非模板函数?
Declare non-template function in a template class?
注意:这篇文章与这篇文章不同:为类外的模板类声明非模板友元函数,所以请在将其标记为重复之前阅读我的问题。
我想在类模板中声明一个非模板友元函数,并且该友元函数的参数和返回类型与模板参数无关。我应该怎么做?
请注意,它与上一个问题不同,因为在该问题中,该 friend 函数的参数和返回类型与模板参数相关。
示例,改编自上面的问题:
// 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()
- 能够在 *.cpp 文件中定义
modify()
,而不是在标头中定义。
接受的答案:
为了实现上述两个目标,不要滥用友谊。
最佳做法是让类模板私下继承非模板基类,并在该基类中声明与模板参数无关的常见非模板方法。
因此,您可以在单独的 *.cpp 文件中定义这些方法,从而减小标头的大小。
您可以使用私有继承而不是友谊:
// 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; }
你这样做是这样的:
// 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;
}
正如我在评论中所说,friend
船控制对类的访问。只要您的函数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';
}
};
}
- Visual Studio中的函数声明和函数定义问题
- 为什么函数声明中允许 const?
- 如果 x.h 仅由函数声明组成,为什么有必要在 x 中包含 x.h.cpp
- * 和 ** 在 C++ 函数声明中是什么意思?
- 构造函数/函数声明参数列表中的统一初始化
- 在将函数声明为友元时,尖括号的含义是什么?
- 为什么转换函数声明不需要至少一个定义类型说明符
- 如何正确编写指针函数声明?
- 在"template"和函数声明之间使用:template<typename trait> using tr = base_trait<trait> void fn(tr::t
- 为什么要将函数声明和定义放在单独的文件中
- 为什么系统日志有两个不同的函数声明?
- 我如何获取数组的大小,以便我可以从函数声明所述数组
- 使用 enable_if 在按值传递与按引用传递之间更改函数声明
- JavaScript 中的一等函数和 C++ 中的函数声明
- C++ 通过函数声明后初始化向量
- VS2017 #error: : snprintf 的宏定义与标准库函数声明冲突
- C++ 17 个友元函数声明和内联命名空间
- MSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的好友
- 将派生类的构造函数声明为父类的友元
- 用于从 ANSI 字符串转换为 std::basic_string <TCHAR>的正确函数声明