Nota: esto debería ir en el subforo de C++. Aquí difícilmente lo van a ver los foreros que programan en C++. Yo lo vi porque me salió la respuesta de arriba en "mensajes recientes".
No sé si aún lo necesites, pero si lo mueven al subforo correcto igual a alguien le sirve después. Antes que nada, el mensaje de arriba, que parece ser copy/paste de ChatGPT-3, es un completo disparate, así que mejor ignorarlo.
Primero, ¿estás seguro de que copiaste bien esto?
friend typename RealType<S>::type foo(C<S> &c);
porque ahí estás declarando como amiga una función normal (no plantilla), que además va a tener precedencia sobre las que declaraste (que son plantillas), así que te debería dar error de enlazado. Si dices que te funciona bien para C<double>, supongo que más bien la declaraste así:
friend typename RealType<S>::type foo<S>(C<S> &c);
que es la forma correcta. Y ahí sí tienes el problema que comentas, porque con estas declaraciones:
template <class S>
typename RealType<S>::type foo(C<S> &c);
template <class S>
typename RealType<std::complex<S> >::type foo(C<std::complex<S> > &c);
nota que el parámetro de tipo para la plantilla
es S en las dos. En ningún caso es std::complex<S>. Lo que el compilador hará será sobrecargar la función foo<S>: una versión recibe un parámetro de tipo C<S>&, y la otra uno de tipo C<std::complex<S> >&. Esto responde a tu otra pregunta: no, no es especialización sino sobrecarga.
Por lo tanto, si tienes algo como esto:
C<double> c_real;
C<std::complex<double> > c_complejo;
foo(c_real);
foo(c_complejo)
las funciones que se generan son (omito los tipos de retorno por legibilidad):
foo<double>(C<double>& c);
foo<double>(C<std::complex<double> >& c);
nota que las dos "se llaman" foo<double>. Sin embargo, en la clase C:
template <class S>
class C
{
friend typename RealType<S>::type foo<S>(C<S> &c);
// ...
};
si declaras una variable C<std::complex<double> >, entonces, en lo que respecta a C, S es igual a std::complex<double>. Por lo tanto, lo que se estaría declarando como amiga es una hipotética función:
foo<std::complex<double> >(C<std::complex<double> >& c);
pero como te dije, la función que declaraste se genera como:
foo<double>(C<std::complex<double> >& c);
que no es amiga de C, y de ahí el error. No sé exactamente qué quieras lograr, pero posiblemente esto sea lo que buscas:
template <class S>
class C
{
friend typename RealType<S>::type foo<typename RealType<S>::type>(C<S>& c);
};
Así, en ambos casos se declararía como amiga foo<double> (siquiendo con los ejemplos), en su versión sobrecargada de acuerdo al tipo de C.