Давайте начнем с того, что отметим, что «предварительное объявление» - это разговорный термин, используемый для обозначения определенного общего практического использования определенных видов объявлений. В отношении стандарта C ++ не существует такой вещи, как предварительное объявление. Есть только декларации.
Имея это в виду, я считаю, что нет никакой разницы между
void foo(struct bar *);
и
struct bar;
, насколько они влияют на имя bar
обеспокоено. Оба объявления в конечном итоге вводят имя структуры bar
, если не существует предыдущего объявления, которое уже сделало это.
Соответствующий абзац в C ++ 17, по-видимому, будет [basi c .lookup.elab] / 2 (выделено мной):
Если описатель сложного типа *1019* введен ключом класса и этот поиск не находит ранее объявленное имя-типа , или […] уточненный-спецификатор типа - это объявление, которое вводит имя-класса как описано в [basi c .scope.pdecl].
Если уточненный спецификатор типа , который не содержит nested-name-спецификатор встречается, поиск по неквалифицированному имени выполняется, чтобы видеть, называет ли имя уже соответствующий тип. Если ранее объявленное имя не найдено, то подробный спецификатор типа становится объявлением типа класса этого имени…
Как указывает geza, единственный способ, которым может быть разница связана с областью, в которой вводится имя. В то время как
struct bar;
всегда вводит имя в область, в которой появляется объявление, подробный спецификатор типа , появляющийся как часть любого другого вида объявления, вводит имя в Ближайшее окружающее пространство имен [basi c .scope.pdecl] / 7 .