Смешивать шаблоны и дружбу не всегда так просто, как может показаться. Мой совет заключается в том, чтобы вы определили функцию с поддержкой друзей в определении класса, и тогда ваша проблема в основном исчезнет:
template <typename T1, typename T2>
struct test {
friend void print( test const & t ) { ... };
};
Для каждого экземпляра шаблона test
он будет объявлять и определять (не шаблонизированную) свободную функцию, которая принимает объект test
, созданный с теми же аргументами шаблона, которые инициировали создание шаблона.
Доступны другие варианты (я бы не стал их использовать, если это возможно):
Вы можете сделать print
шаблоном и объявить этот шаблон другом вашего шаблона класса (всего шаблона):
template <typename T1, typename T2>
struct test {
template <typename U, typename V>
friend void foo( test<U,V> const & ); // befriend template, all instantiations
};
template <typename T1, typename T2>
void foo( test<X,Y> const & x ) {...}
Это открывает ваши внутренние возможности для всех возможных реализаций шаблона, включая возможные специализации, и вы, возможно, не захотите этого делать. Если вы хотите подружиться только с конкретным экземпляром этого шаблона, вы можете сделать это, но он становится более громоздким:
template <typename T1, typename T2> struct test; // forward declaration
template <typename T1, typename T2>
void foo( test<T1,T2> const & ); // forward declaration
template <typename T1, typename T2>
struct test {
friend void foo<T1,T2>( test<T1,T2> const & ); // befriend specific instantiation
};
template <typename T1, typename T2>
void foo( test<T1,T2> const & x ) { ... } // implement
Дополнительное объяснение вы можете найти в ответе здесь