Участник:Joparino/Barton–Nackman trick: различия между версиями
Joparino (обсуждение | вклад) Нет описания правки |
Joparino (обсуждение | вклад) Нет описания правки |
||
Строка 1: | Строка 1: | ||
'''''Трюк Бартона—Накмана''''' ({{lang-en|Barton–Nackman trick}}) термин придуманный комитетом по стандартизации C++ ([[ISO/IEC JTC1/SC22]] WG21) для обозначения [[Идиома (программирование)|идиомы]] |
'''''Трюк Бартона—Накмана''''' ({{lang-en|Barton–Nackman trick}}) термин, придуманный комитетом по стандартизации C++ ([[ISO/IEC JTC1/SC22]] WG21) для обозначения [[Идиома (программирование)|идиомы]], введённой Джоном Бартоном и Ли Накманом как ''ограниченное расширение шаблона''<ref>{{cite book |last1=Barton |first1=John J. |last2=Nackman |first2=Lee R. |title=Scientific and Engineering C++: An Introduction with Advanced Techniques and Examples |publisher=[[Addison-Wesley]] |year=1994 |isbn=0-201-53393-6}}</ref>. |
||
==Идиома== |
==Идиома== |
||
Идиома характеризуется определением |
Идиома характеризуется определением внутри класса дружественной функции, находящейся в шаблоне базового класса. Это является примером использования [[curiously recurring template pattern|рекурсивного шаблона]] ({{lang-en|curiously recurring template pattern, CRTP}}). |
||
<syntaxhighlight lang="cpp"> |
<syntaxhighlight lang="cpp"> |
||
// Шаблон класса |
// Шаблон класса для сравнения на равенство. |
||
template<typename T> class equal_comparable { |
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); } |
Версия от 08:41, 8 июля 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); }
};
// Class value_type wants to have == and !=, so it derives from
// equal_comparable with itself as argument (which is the CRTP).
class value_type : private equal_comparable<value_type> {
public:
bool equal_to(value_type const& rhs) const; // to be defined
};
When a class template like equal_comparable
is instantiated, the in-class friend definitions produce nontemplate (and nonmember) functions (operator functions, in this case). At the time the idiom was introduced (1994), the C++ language did not define a partial ordering for overloaded function templates and, as a result, overloading function templates often resulted in ambiguities. For example, trying to capture a generic definition for operator==
as
template<typename T>
bool operator==(T const &a, T const &b) {
/* ... */
}
would essentially be incompatible with another definition like
template<typename T>
bool operator==(Array<T> const &a, Array<T> const &b) {
/* ... */
}
The Barton–Nackman trick, then, achieves the goal of providing a generic user-defined equality operator without having to deal with such ambiguities. The adjective restricted in the idiom name refers to the fact that the provided in-class function definition is restricted (only applies) to specializations of the given class template.
The term is sometimes mistakenly used to refer to the curiously recurring template pattern (CRTP). As explained above, the Barton–Nackman trick is, instead, a distinct idiom (that relies on the CRTP).
How it works
When the compiler encounters the expression
v1 == v2
where v1
and v2
are of type value_type
, it attempts argument-dependent lookup (ADL) for operator==
. This lookup includes consideration of friend functions declared in value_type
and its base classes. (Note that if value_type
were an incomplete template instance, ADL would trigger its complete instantiation.)
The Barton–Nackman trick originally relied not on ADL but on a C++ feature called "friend name injection", in which an in-class declaration of a friend function made the function name visible in the immediately surrounding namespace scope (possibly the global scope). When investigating the possibility of removing friend name injection from the C++ programming language, Barton and Nackman's idiom was found to be the only reasonable use of that language rule. Eventually, the rules for argument-dependent lookup were adjusted[2] to replace friend name injection by a less drastic mechanism, described above, that maintained the validity of Barton and Nackman's technique. It is worth noting that, as a consequence of this change, the expression
::operator==(v1,v2)
is no longer valid, because qualified names aren't subject to ADL and friend declarations aren't found via ordinary lookup. Note, too, that the friend
specifier is essential, even if the defined friend functions do not actually need to access nonpublic members of the befriending class.
See also
References
- ↑ 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.
Further reading
- Vandevoorde, David. C++ Templates: The Complete Guide / David Vandevoorde, Nicolai M. Josuttis, Douglas Gregor. — 2. — Addison-Wesley, 2017. — ISBN 978-0-321-71412-1.