巴顿-纳克曼trick俩的一个例子

2020-12-16 14:07:13

我仍然需要写博客文章来解释“什么是隐藏的朋友成语?”;但是现在,这是cpplang Slack上的实用示例的实际演示(感谢Johan Lundberg!)。

考虑这对类别模板Cat< T>。和DogT。 Cat与STL的容器模板类似,后者定义了操作符< (或在C ++ 20中,operator =)作为自由函数模板。

template< class V> struct Cat {V value_;}; template< class V> bool运算符<(const Cat< V& a,const cat< V>& b){返回a.value_< b.value_;}

模板< class V>结构狗{V value_;朋友布尔运算符<(const Dog& a,const Dog& b){return a.value_< b.value_; }};

现在考虑以下“ sort_in_place”算法,该算法使用reference_wrapper对指向其const参数向量的句柄向量进行排序,而不是对参数vector本身进行排序。 (我从来没有发现此技巧在实践中有用,但是非常可爱地展示了STL的各个部分如何组合在一起。我在“经典STL”培训课程的reference_wrapperunit中基本上使用了此代码。)

模板<类T>无效sort_in_place(const std :: vector< t>> vt){std :: vector< std :: reference_wrapper< const T> vr(vt.begin(),vt.end()); std :: sort(vr.begin(),vr.end()); std :: transform(vr.begin(),vr.end(),std :: ostream_iterator< int>(std :: cout),std :: mem_fn(& T :: value_));}

我们观察到sort_in_place对于Dog来说效果很好。每当std :: sort需要计算< b,其中a和b是reference_wrapper< Dog<>>&gt ;,它使用ADL来找到我们的朋友作为候选者,然后确认reference_wrapper< Dog< int>确实可隐式转换为const Dog< int> amp ;对于两个参数。

但是对Cat来说sort_in_place失败了!它仍然使用ADL查找我们的操作符< template;。但是,模板自变量推导要求提供的自变量类型与模板指定的模式完全匹配,在这种情况下,这是不正确的-没有V使得Cat< V>是reference_wrapper< Cat< Cat> int>。推论失败。

我们可以通过写operator<来手动调用适当的专业化-V = int的专业化。 < int>(vr [0],vr [1])。 (那里的空间很重要!)但是我们不能简单地写vr [0]< vr [1]因为与模板参数推导的这种不良交互作用。

因此,Dog的运算符<至少在这方面比Cat的设计更好。

隐藏的朋友习语的主要好处是,它避免了成员运算符对左右操作数的不对称处理,并且通过不将自由运算符直接转储到顶级命名空间中来缩小重载集。此博客与以上任何一项都不相关。

在像Dog这样的情况下使用隐藏的朋友习惯用法(专门用于创建实例化与非模板朋友相关联的类模板)被称为“巴顿-纳克曼技巧”。这篇博客文章显示了Barton-Nackman技巧的一种方式,特别是提供了微妙的好处。

即使在C ++ 20中,STL容器通常也使用免费模板而不是Barton-Nackman技巧,这意味着sort_in_place将在vt为vector 时工作,但在vt为vector 时失败。 (天哪。)