Русская Википедия:Трюк Бартона — Накмана
Трюк Бартона — Накмана (Шаблон:Lang-en) термин, придуманный комитетом по стандартизации C++ (ISO/IEC JTC1/SC22 WG21) для обозначения идиомы, введённой Джоном Бартоном и Ли Накманом как ограниченное расширение шаблона[1].
Идиома
Идиома характеризуется определением внутри класса дружественной функции, находящейся в шаблоне базового класса. Это является примером использования рекурсивного шаблона (Шаблон:Lang-en).
// Шаблон класса для сравнения на равенство.
template<typename T> class equal_comparable {
friend bool operator==(T const &a, T const &b) { return a.equal_to(b); }
friend bool operator!=(T const &a, T const &b) { return !a.equal_to(b); }
};
// Класс value_type имеет == и !=, поэтому он является производным от
// equal_comparable с самим собой в качестве аргумента (который является CRTP).
class value_type : private equal_comparable<value_type> {
public:
bool equal_to(value_type const& rhs) const; // Требует определения
};
Когда создается экземпляр шаблонного класса, такого как equal_comparable
, определения друзей внутри класса (Шаблон:Lang-en) порождают нешаблонные (и не являющиеся членами) функции (в данном случае функции-операторы). На момент появления идиомы (1994) язык C++ не определял частичный порядок (Шаблон:Lang-en) для перегруженных шаблонов функций, и, как следствие, перегрузка шаблонов функций часто приводила к неоднозначности. Например, попытка использовать общее определение для operator==
как:
template<typename T>
bool operator==(T const &a, T const &b) {
/* ... */
}
была бы несовместима с другим определением, таким как:
template<typename T>
bool operator==(Array<T> const &a, Array<T> const &b) {
/* ... */
}
Таким образом, трюк Бартона — Накмана предоставляет шаблонный оператор равенства, определённый пользователем, без необходимости иметь дело с такими неоднозначностями. Прилагательное ограниченный (Шаблон:Lang-en) в названии идиомы относится к тому факту, что определение функции, находящееся внутри класса (Шаблон:Lang-en), ограничено (применяется только) к специализациям данного шаблона класса.
Этот термин иногда ошибочно используется для обозначения рекурсивного шаблона (CRTP). Как объяснялось выше, трюк Бартона — Накмана — это отдельная идиома (которая опирается на CRTP).
Механизм работы
Когда компилятор сталкивается с выражением
v1 == v2
где v1
и v2
имеют тип value_type
, компилятор пытается выполнить поиск, зависящий от аргументов (Шаблон:Lang-en) для operator==
. Этот поиск включает в себя рассмотрение дружественных функций, объявленных в value_type
и в его базовых классах. (Заметим, что, если value_type
был бы неполным экземпляром шаблона, ADL вызвал бы его полное инстанцирование.)
Трюк Бартона — Накмана изначально основывался не на ADL, а на особенности C++, названной «инъекция имени друга» (Шаблон:Lang-en), в которой объявление дружественной функции внутри класса делало имя функции видимым в непосредственно окружающем пространстве имён (возможно, в глобальной области). При рассмотрении возможности удалить инъекцию имени друга из языка C++ было обнаружено, что идиома Бартона — Накмана — единственное оправданное применение этого языкового правила. В итоге были скорректированы правила поиска, зависящего от аргумента[2], так, чтобы заменить инъекцию имени друга менее радикальным механизмом, описанным выше, который поддерживал работоспособность метода Бартона и Накмана. Стоит отметить, что, как следствие этого изменения, выражение:
::operator==(v1,v2)
больше не является допустимым, поскольку квалифицированные имена не подпадают под действие ADL, а объявления друзей не могут быть найдены с помощью обычного поиска. Заметим также, что спецификатор friend
необходим, даже если дружественные функции не нуждаются в доступе к закрытым и защищённым членам класса.
См. также:
Ссылки
Дополнительно