В С++, почему нет возможности связать функцию члена класса шаблона с использованием типа шаблона другого класса?
Другими словами, почему это компилируется отлично:
template<typename Type>
class A{
public:
void f();
};
class B{
friend void A<int>::f();
};
template<>
void A<int>::f(){
B* var = new B();
}
Пока это не так:
template<typename Type>
class A{
public:
void f();
};
template<typename Type> // B is now a templated class
class B{
friend void A<Type>::f(); // Friending is done using B templated type
};
template<>
void A<int>::f(){
B<int>* var = new B<int>(); // var is now declared using int as its templated type
}
Для второго фрагмента кода компилятор (gcc 6.2, без специальных флагов) говорит:
main.cpp: In instantiation of ‘class B<int>’:
main.cpp:14:28: required from here
main.cpp:9:15: error: prototype for ‘void A<int>::f()’ does not match any in class ‘A<int>’
friend void A<Type>::f();
^~~~~~~
main.cpp:13:6: error: candidate is: void A<Type>::f() [with Type = int]
void A<int>::f(){
Как я понимаю, во втором фрагменте кода при объявлении var компилятор должен проанализировать объявление класса B, замените тип, используемый в объявлении друга int, и все должно работать нормально. Что мне не хватает?
EDIT: комментарии ниже указали, что второй фрагмент кода, похоже, правильно компилируется с помощью clang и Visual С++ 2015
Ответы
Ответ 1
Явное создание экземпляра B<int>
до его использования в A<int>::f()
устраняет эту проблему. Я предполагаю, что GCC пытается выполнить неявное создание B<int>
в определении A<int>::f()
. Но определение A<int>::f()
не завершено, и GCC "теряет" декларацию друга. Это похоже на проблему с компилятором.
template<typename Type>
class A
{
public:
void f();
};
template<typename Type> // B is now a templated class
class B
{
friend void A<Type>::f(); // Friending is done using B templated type
};
template
class B<int>; // <= explicit instantiation, that works
template<>
void A<int>::f()
{
B<int>* var = new B<int>();
}
Ответ 2
Специализирующая функция template class
member без специализированного целого template class
- это особый случай, когда вам разрешено специализироваться на функции не template
, поэтому, возможно, GCC
запутано, и я не знаю причин, но так или иначе вы не можете объявить дружбу специализированному члену template
<<20 > . Временным решением будет специализироваться на целом class template
, чтобы это работало.
//class template A
template<typename Type>
class A{
public:
void f();
};
//class A<int>
template<>
class A<int>{
public:
void f();
};
Затем определите A<int>::f
:
Для class B:
void A<int>::f(){
B* var = new B();
(void)(var);
}
Для template class B
:
void A<int>::f(){
B<int>* var = new B<int>();
(void)(var);
}
Но я думаю, что Clang
здесь, не должно быть никаких проблем для такого объявления друга. Вероятно, это ошибка в GCC
.