Escribo esto como una respuesta separada en lugar de solo un comentario porque no estoy de acuerdo con la respuesta de Luc Touraille, no por razones de legalidad, sino por un software robusto y el peligro de una mala interpretación.
Específicamente, tengo un problema con el contrato implícito de lo que usted espera que los usuarios de su interfaz tengan que saber.
Si está devolviendo o aceptando tipos de referencia, solo está diciendo que pueden pasar a través de un puntero o referencia que a su vez pueden haber conocido solo a través de una declaración directa.
Cuando devuelve un tipo incompleto X f2();
, está diciendo que la persona que llama debe tener la especificación de tipo completo de X. La necesita para crear el LHS u objeto temporal en el sitio de la llamada.
Del mismo modo, si acepta un tipo incompleto, la persona que llama debe haber construido el objeto que es el parámetro. Incluso si ese objeto se devolvió como otro tipo incompleto de una función, el sitio de la llamada necesita la declaración completa. es decir:
class X; // forward for two legal declarations
X returnsX();
void XAcceptor(X);
XAcepptor( returnsX() ); // X declaration needs to be known here
Creo que hay un principio importante de que un encabezado debe proporcionar suficiente información para usarlo sin una dependencia que requiera otros encabezados. Eso significa que el encabezado debería poder incluirse en una unidad de compilación sin causar un error de compilación cuando utilice cualquier función que declare.
Excepto
Si esta dependencia externa es el comportamiento deseado . En lugar de utilizar la compilación condicional, podría tener un requisito bien documentado para que proporcionen su propio encabezado declarando X. Esta es una alternativa al uso de #ifdefs y puede ser una forma útil de introducir simulacros u otras variantes.
La distinción importante son algunas técnicas de plantilla en las que NO se espera explícitamente que las instancia, mencionada solo para que alguien no se vuelva sarcástico conmigo.