Шаблон, в котором имеется несколько точек настройки, для каждой из них может выбрать свою стратегию, в наибольшей мере приемлемую в данном месте. Главное, что вы должны осознанно, с пониманием выбирать стратегию для каждой точки настройки, документировать требования к настройке (включая ожидаемые постусловия и семантику ошибок) и корректно реализовать выбранную вами стратегию.
Для того чтобы избежать непреднамеренных точек настройки, следует придерживаться следующих правил.
•
template
void Samplе4(T t) {
S4Helpers::bar(t); // Запрет ADL: bar не является
// точкой настройки
(bar)(t); // Альтернативный способ
}
• T
в случае template
) или от типа, который построен с использованием одного из параметров шаблона (например, X
в случае template
).
Коротко говоря, при обращении к любому члену зависимого базового класса необходимо всегда явно квалифицировать имя с использованием имени базового класса или при помощи this->
. Этот способ можно рассматривать просто как некую магию, которая заставляет все компиляторы делать именно то, что вы от них хотите.
template
class С : X
typename X
// типа (или синонима
// typedef) из базового
// класса
public:
void f() {
X
// базового класса
this->baz(); // Альтернативный способ
}
};
Стандартная библиотека С++ в основном отдает предпочтение варианту 2 (например, ostream_iterator
ищет оператор operator<<
, a accumulate
ищет оператор operator+
в пространстве имен вашего типа). В некоторых местах стандартная библиотека использует также вариант 3 (например, iterator_traits
, char_traits
) в основном потому, что эти классы свойств должны быть специализируемы для встроенных типов.
Заметим, что, к сожалению, стандартная библиотека С++ не всегда четко определяет точки настройки некоторых алгоритмов. Например, она ясно говорит о том, что трехпараметрическая версия accumulate
должна вызывать пользовательский оператор operator+
с использованием второго варианта. Однако она не говорит, должен ли алгоритм sort
вызывать пользовательскую функцию swap
(обеспечивая таким образом преднамеренную точку настройки с использованием варианта 2),swap
, и вызывает ли он функцию swap
вообще; на сегодняшний день некоторые реализации sort
используют пользовательскую функцию swap
, в то время как другие реализации этого не делают. Важность рассматриваемой рекомендации была осознана совсем недавно, и сейчас комитет по стандартизации исправляет ситуацию, устраняя такие нечеткости из стандарта. Не повторяйте такие ошибки. (См. также рекомендацию 66.)
66. Не специализируйте шаблоны функций