外部模板类和非模板友元函数

Extern template class and non-template friend functions

本文关键字:友元 函数 外部      更新时间:2023-10-16

我已经开始玩extern模板了,我偶然发现了一个问题,我找不到任何相关信息。假设我有一个带有非模板友元函数的类模板(在类模板声明中定义)。我为类声明了一些extern模板实例化,但如何将友元函数也声明为extern?

以下是一些示例代码:

// --- test.h ---
template <typename T>
class Foo {
private:
T value;
public:
friend void some_friend_function(Foo<T>& obj) {
obj.value -= T(42);
};
void some_member_function(T rhs) { value += rhs; };
};
extern template class Foo<int>;
//extern void some_friend_function(Foo<int>&);  // I tried this also...

// --- test.cpp ---
#include "test.h"
template class Foo<int>;
//void some_friend_function(Foo<int>&);         // ... with this.

当我编译上面的(有或没有注释行)时,我只得到以下导出的符号:

0000000000000000 W _ZN3FooIiE20some_member_functionEi

因此,非模板友元函数肯定不会随着类模板的显式实例化而实例化(和extern'd)。这正常吗?至少,这就是GCC产生的结果(在4.6.3和4.7.2中进行了测试)

有没有什么方法可以让friend函数标记为extern?我知道这不是一个大问题,因为我可以很高兴地接受根据需要实例化的朋友函数(即非外部函数),但我很想知道是否有办法做到这一点,如果没有,这是疏忽还是故意的?

EDIT:显而易见的解决方案

我的问题特别是关于非模板朋友函数,而不是关于找到一个解决方法来避免这个问题,这是微不足道的。第一个明显的解决方法是:

template <typename T>
class Foo {
private:
T value;
public:
template <typename U>
friend void some_friend_function(Foo<U>& obj) {
obj.value -= T(42);
};
};
extern template class Foo<int>;
extern template void some_friend_function(Foo<int>&);
// --- in cpp file: ---
template class Foo<int>;
template void some_friend_function(Foo<int>&);

另一个匹配更紧密但更麻烦的是:

template <typename T> class Foo;  // forward-declare.
template <typename T>
void some_friend_function(Foo<T>&);  // declaration.
template <typename T>
class Foo {
private:
T value;
public:
friend void some_friend_function<>(Foo<T>& obj);  // befriend the T-specialization.
};
template <typename T>
void some_friend_function(Foo<T>& obj) {  // definition.
obj.value -= T(42);
};
extern template class Foo<int>;
extern template void some_friend_function(Foo<int>&);
// --- in cpp file: ---
template class Foo<int>;
template void some_friend_function(Foo<int>&);

"外部模板类"的作用是声明显式实例化可用。显式实例化声明的效果不适用于内联函数或模板专业化(14.7.2[temp.extic]第10段):

除了内联函数和类模板专门化之外,显式实例化声明具有抑制其引用的实体的隐式实例化的效果。

由于类定义中的friend函数定义必然是inline函数,因此它将保持inline函数独立于模板的显式实例化声明(而且,正如您正确指出的,它不是模板,也不遵循模板实例化规则)。