テンプレートを少しいじり始め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 でテスト済み)。
フレンド関数を extern とマークする方法はありますか? これは大きな問題ではないことはわかっています。なぜなら、必要に応じてインスタンス化されたフレンド関数 (つまり、extern 以外) とうまくやっていくことができるからです。 、それは見落としか意図的なものでしたか?
編集:明らかな回避策
私の質問は、特に問題を回避するための回避策を見つけることではなく、テンプレート以外のフレンド機能に関するものです。これは些細なことです。最初の明らかな回避策は次のとおりです。
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>&);