Я начал играть с 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>&);
Эффект «внешнего шаблона класса» заключается в объявлении явного экземпляра доступным. Эффект явных объявлений создания экземпляров не применяется к встроенным функциям или специализациям шаблонов (14.7.2 [temp.explicit] параграф 10):
За исключением встроенных функций и специализаций шаблонов классов, явные объявления экземпляров подавляют неявное создание экземпляров сущности, к которой они относятся.
Так как friend
Определение функции в определении класса обязательно inline
функция, она останется inline
функция не зависит от явного объявления экземпляра шаблона (и, как вы правильно заметили, это не шаблон и в любом случае не следует правилам создания экземпляра шаблона).
Других решений пока нет …