Я пишу это как отдельный ответ, а не просто как комментарий, потому что я не согласен с ответом Люка Турайля не по законности, а по поводу надежного программного обеспечения и опасности неверного толкования.
В частности, у меня есть проблема с подразумеваемым договором о том, что, как вы ожидаете, должны знать пользователи вашего интерфейса.
Если вы возвращаете или принимаете ссылочные типы, то вы просто говорите, что они могут проходить через указатель или ссылку, которые они, в свою очередь, могут знать только через предварительную декларацию.
Когда вы возвращаете неполный тип X f2();
, вы говорите, что ваш вызывающий должен иметь полную спецификацию типа X. Им это нужно для создания LHS или временного объекта на сайте вызова. .
Аналогичным образом, если вы принимаете неполный тип, вызывающая сторона должна создать объект, который является параметром. Даже если этот объект был возвращен из функции как еще один неполный тип, сайту вызова необходимо полное объявление. i.e.:
class X; // forward for two legal declarations
X returnsX();
void XAcceptor(X);
XAcepptor( returnsX() ); // X declaration needs to be known here
Я думаю, что есть важный принцип, что заголовок должен предоставлять достаточно информации, чтобы использовать его без зависимости, требующей других заголовков. Это означает, что заголовок должен быть включен в модуль компиляции, не вызывая ошибки компилятора при использовании любых функций, которые он объявляет.
За исключением
Если эта внешняя зависимость является желаемым поведением. Вместо условной компиляции у вас может быть хорошо документированное требование , чтобы они предоставили свой собственный заголовок, объявляющий X. Это альтернатива использованию #ifdefs и может быть полезным способом представить mock или другие варианты.
Важным отличием является то, что некоторые шаблонные приемы, в которых вы явно НЕ должны создавать их экземпляры, упоминаются просто для того, чтобы кто-то не стал со мной злобным.