Участник:Joparino/Barton–Nackman trick: различия между версиями
Joparino (обсуждение | вклад) Нет описания правки |
Joparino (обсуждение | вклад) Нет описания правки |
||
Строка 54: | Строка 54: | ||
больше не является допустимым, поскольку квалифицированные имена не подпадают под действие ADL, а объявления друзей не могут быть найдены с помощью обычного поиска. Обратите также внимание, что спецификатор <code>friend</code> необходим, даже если определенные функции друзей на самом деле не нуждаются в доступе к непубличным членам дружественного класса. |
больше не является допустимым, поскольку квалифицированные имена не подпадают под действие ADL, а объявления друзей не могут быть найдены с помощью обычного поиска. Обратите также внимание, что спецификатор <code>friend</code> необходим, даже если определенные функции друзей на самом деле не нуждаются в доступе к непубличным членам дружественного класса. |
||
== |
==См. также:== |
||
* [[Curiously recurring template pattern]] |
* [[Curiously recurring template pattern]] |
||
Версия от 09:16, 12 июля 2022
Трюк Бартона—Накмана (англ. Barton–Nackman trick) термин, придуманный комитетом по стандартизации C++ (ISO/IEC JTC1/SC22 WG21) для обозначения идиомы, введённой Джоном Бартоном и Ли Накманом как ограниченное расширение шаблона[1].
Идиома
Идиома характеризуется определением внутри класса дружественной функции, находящейся в шаблоне базового класса. Это является примером использования рекурсивного шаблона (англ. curiously recurring template pattern, CRTP).
// Шаблон класса для сравнения на равенство.
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; // to be defined
};
Когда создается экземпляр шаблонного класса, такого как equal_comparable, определения друзей в классе создают функции, не являющиеся шаблонными (и не являющиеся членами) (в данном случае функции оператора). На момент появления идиомы (1994) язык C++ не определял частичный порядок для перегруженных шаблонов функций, и, как следствие, перегрузка шаблонов функций часто приводила к неоднозначности. Например, попытка захватить общее определение для 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) {
/* ... */
}
Таким образом, трюк Бартона–Накмана достигает цели предоставления общего пользовательского оператора равенства без необходимости иметь дело с такими двусмысленностями. Прилагательное ограниченный в названии идиомы относится к тому факту, что предоставленное определение функции в классе ограничено (применяется только) к специализациям данного шаблона класса.
Этот термин иногда ошибочно используется для обозначения рекурсивного шаблона (CRTP). Как объяснялось выше, трюк Бартона–Накмана — это отдельная идиома (которая опирается на CRTP).
Как это работает
Когда компилятор сталкивается с выражением
v1 == v2
Где v1
и v2
имеют тип value_type
, компилятор пытается выполнить поиск, зависящий от аргументов (англ. argument-depend lookup, ADL) для operator==
. Этот поиск включает в себя рассмотрение дружественных функций, объявленных в value_type
и в его базовых классах. (Обратите внимание, что если value_type
был неполным экземпляром шаблона, ADL вызовет его полное создание.)
Трюк Бартона-Накмана изначально основывался не на ADL, а на особенности C++ названной "инъекция имени друга", в которой объявление дружественной функции в классе делало имя функции видимым в непосредственно окружающей области пространства имен (возможно, в глобальной области). При исследовании возможности удаления инъекции имени друга из языка программирования C++ было обнаружено, что идиома Бартона и Накмана была признана единственным разумным использованием этого языкового правила. В итоге, были скорректированы правила поиска, зависящего от аргумента[2], чтобы заменить инъекцию имени друга менее радикальным механизмом, описанным выше, который поддерживал правильность метода Бартона и Накмана. Стоит отметить, что, как следствие этого изменения, выражение:
::operator==(v1,v2)
больше не является допустимым, поскольку квалифицированные имена не подпадают под действие ADL, а объявления друзей не могут быть найдены с помощью обычного поиска. Обратите также внимание, что спецификатор friend
необходим, даже если определенные функции друзей на самом деле не нуждаются в доступе к непубличным членам дружественного класса.
См. также:
Литература
- ↑ Barton, John J. Scientific and Engineering C++: An Introduction with Advanced Techniques and Examples / John J. Barton, Lee R. Nackman. — Addison-Wesley, 1994. — ISBN 0-201-53393-6.
- ↑ An Alternative to Name Injection from Templates (26 сентября 1995). Дата обращения: 12 апреля 2005.
Дополнительно
- Vandevoorde, David. C++ Templates: The Complete Guide / David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor. — 2. — Addison-Wesley, 2017. — ISBN 978-0-321-71412-1.