Просто приведу несколько примеров сказанного: контейнеры STL.
typedef std::map<int,Froboz> tFrobozMap;
tFrobozMap frobozzes;
...
for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
{
...
}
Нет ничего необычного в том, чтобы даже использовать typedefs вроде
typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;
Другой пример: использование общих указателей:
class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;
[обновление] Согласно комментарию - где их разместить?
Последний пример - использование shared_ptr
- прост: это настоящий материал заголовка или, по крайней мере, прямой заголовок. В любом случае вам необходимо предварительное объявление для shared_ptr, и одно из объявленных преимуществ заключается в том, что его можно безопасно использовать с предварительным decl.
Другими словами: если есть shared_ptr, вы, вероятно, должны использовать тип только через shared_ptr, поэтому разделение объявлений не имеет особого смысла.
(Да, xyzfwd.h - это боль. Я бы использовал их только в горячих точках - зная, что горячие точки трудно идентифицировать. Виноват C ++ компиляция + модель ссылок ...)
Определения типа контейнера, которые я обычно использую, когда объявляется переменная контейнера - например, локально для локальной переменной, как члены класса, когда фактический экземпляр контейнера является членом класса. Это хорошо работает, если фактический тип контейнера является деталью реализации, не вызывая дополнительной зависимости.
Если они становятся частью определенного интерфейса, они объявляются вместе с интерфейсом, с которым они используются, например,
// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes);
Это становится проблематичным, когда тип является элементом привязки между различными интерфейсами - то есть один и тот же тип необходим для нескольких заголовков. Некоторые решения:
- объявить его вместе с содержащимся типом
(подходит для контейнеров, которые часто используются для этого типа)
- переместить их в отдельный заголовок
- перейти к отдельному заголовку и сделать его классом данных, где реальный контейнер снова является деталью реализации
Я согласен, что два последних не так уж и хороши, я бы использовал их только тогда, когда у меня возникнут проблемы (не проактивно).