Простой ответ: сделайте typedef общедоступным.
Это приведет к утечке незначительных деталей реализации (фактический внутренний тип), но поскольку он определен по типу, вы можете переопределить его в любое время, и все должно быть в порядке.
Немного менее просто: воспользуйтесь вспомогательной функцией, обеспечивающей доступ к вашему внутреннему типу.
Проблема с этим вторым подходом заключается в том, что вы предоставляете не только доступ к typedef, но и ко всем закрытым частям вашего класса, и это может быть не самой лучшей идеей. В любом случае, поскольку это внутренняя вспомогательная функция, она находится под вашим собственным контролем, и с ней все должно быть в порядке. (Теперь, когда я думаю об этом, вы можете объявить функцию в именованном пространстве имен, чтобы объявление friend
было успешным)
Еще менее просто: создайте отдельную typedef внутри файла реализации и убедитесь, что они синхронизированы.
Вы можете убедиться, что типы совпадают с небольшим битом метапрограммирования, с шаблоном same_type<T,U>
, который предоставит значение true
, если оба типа одинаковы, и false в противном случае. Статическое утверждение вызовет ошибку, если typedef изменяется только в одном месте
Вернемся к простому: предоставьте typedef или используйте тип напрямую без статического утверждения.
Вы вызываете функцию (это не должен быть шаблон, как в вашем коде) и передаете ссылку. Если typedef изменится в классе, вызов не удастся, и компилятор скажет вам.
Я бы выбрал последний вариант, хотя он может показаться немного грубым и менее деликатным , чем другие, но дело в том, что это только деталь реализации, которая не используется другими, вы под полным контролем кода и хорошо, просто лучше.
РЕДАКТИРОВАТЬ , после комментария.
Я начал писать это как комментарий, но он стал слишком длинным, поэтому я добавляю его в ответ.
В этом решении нет ничего плохого, кроме того, что вы без необходимости делаете функцию универсальной, а некоторые сообщения об ошибках в будущем могут быть не такими простыми, как с неуниверсальной сигнатурой. Обратите внимание, что template
будет не выставлять typedef
(как предполагает заголовок вопроса), а скорее сделает компилятор вывод типом в месте вызова.
Если вы измените typedef
, вместо того, чтобы получить сообщение о том, что аргументы helperFn
не могут быть сопоставлены с существующей функцией, тип будет выведен, а функция сопоставлена, но вы получите ошибку глубже helperFn
если вы используете свойство того типа, которого больше нет. Или, что еще хуже, вы можете даже не получить ошибку, если изменилась семантика типа.
Учтите, что typedef имеет значение std::list<X>
и что в функции, которую вы перебираете, с этим простым корректным циклом for:
for (typename T::iterator it=x.begin(), end=x.end(); it != end; ) {
if ( condition(*it) )
it = x.erase(it);
else
++it;
}
Можете ли вы уловить эффект изменения typedef на std::vector<X>
? Компилятор не может, даже если код сейчас неверен. Является ли написание цикла for подобной идеей, или почему это не просто использование erase-remove идиома - это разные проблемы (на самом деле предыдущий цикл возможно лучше чем стереть-удалить для списка), конкретная ситуация заключается в том, что семантика изменилась, и поскольку тип синтаксически совместим с предыдущим, компилятор не заметит, что код неправильный, он не укажет вам на эту функцию, и есть вероятность, что вы не будете его пересматривать / переписывать.