教材我注意到,您可以通过模板专门化为函数重载提供您自己的标准库函数实现,如swap(x,y)
。这对任何可以从除赋值转换外的其他类型受益的类型都很有用,例如STL containers
(已知有交换,我知道)。模板专精VS函数重载
我的问题是:
更棒的是:模板专门给你的专业 交换实现,或者函数重载提供你希望没有模板的确切 参数?
为什么它更好?或者如果他们是平等的,为什么呢?
教材我注意到,您可以通过模板专门化为函数重载提供您自己的标准库函数实现,如swap(x,y)
。这对任何可以从除赋值转换外的其他类型受益的类型都很有用,例如STL containers
(已知有交换,我知道)。模板专精VS函数重载
我的问题是:
更棒的是:模板专门给你的专业 交换实现,或者函数重载提供你希望没有模板的确切 参数?
为什么它更好?或者如果他们是平等的,为什么呢?
小故事:当你可以超载时,专门在你需要的时候。长篇小说:C++对待专业化和重载的方式非常不同。这可以用一个例子来解释。
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <> void foo<int>(int*); // specialisation of foo(T*)
foo(new int); // calls foo<int>(int*);
现在让我们换掉最后两个。
template <typename T> void foo(T);
template <> void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)
foo(new int); // calls foo(T*) !!!
编译器在重载分辨率之前甚至查看专业化。所以,在这两种情况下,重载解决方案都会选择foo(T*)
。但是,只有在第一种情况下才会发现foo<int*>(int*)
,因为在第二种情况下,int*
专业化是foo(T)
的专门化,而不是foo(T*)
。
您提到过std::swap
。这使事情变得更加复杂。
该标准说您可以将专门化添加到std
命名空间。太棒了,所以你有一些Foo
类型,它有一个高性能的交换,那么你只需在std
命名空间中专门设置swap(Foo&, Foo&)
。没问题。
但是,如果Foo
是模板类呢? C++没有部分功能的专业化,所以你不能专注于swap
。你唯一的选择是超载,但标准说你不允许在std
命名空间中添加重载!
你必须在这一点上两个选项:
创建自己的命名空间的swap(Foo<T>&, Foo<T>&)
功能,并希望它得到通过ADL找到。我说“希望”,因为如果标准库调用像std::swap(a, b);
那样的交换,那么ADL根本无法工作。
忽略标准中说不添加重载的部分,并且无论如何都要这样做。老实说,即使它在技术上是不允许的,但在所有现实的情况下,它都会起作用。
但要记住的一件事是,不能保证标准库完全可以使用swap
。大多数算法使用std::iter_swap
,在我看过的一些实现中,它并不总是转发到std::swap
。
您不允许在std
命名空间中重载函数,但允许您专门化模板(我记得),所以这是一种选择。
另一种选择是在调用非限定交换之前,将swap
函数放在与其运行的函数相同的名称空间中,并将其与using std::swap;
相同。
彼得亚历山大的答案几乎没有添加。让我仅仅提到一个使用这个功能的专业化可能会优于超载:如果您必须在没有参数的函数中选择。
例如
template<class T> T zero();
template<> int zero() { return 0; }
template<> long zero() { return 0L; }
要使用函数重载做同样的事情,你将有一个参数添加到函数签名:
int zero(int) { return 0; }
long zero(long) { return 0L; }
有趣的用法:) –
很好的例子先生 – tenfour
“我说希望,因为” ...这一点指出在几年前的WG21中。所有标准库实现者都不知道。 – MSalters
精彩的回答,非常感谢。 –