模板专精VSfunction重载
一本教科书我注意到,你可以提供自己的实现标准库函数,如swap(x,y)
通过模板专门化function重载。 这对任何可以从除了赋值交换以外的其他types都有用的types是有用的,比如STL containers
(已经有了交换,我知道)。
我的问题是:
-
有什么更好的:模板专门化给你的专门的交换实现,或function重载,提供了你想使用没有模板的确切参数?
-
为什么更好? 或者如果他们是平等的,为什么呢?
小故事:当你可以超载的时候,当你需要的时候专门化。
长话短说: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*) !!!
编译器甚至在重视专业化之前做了重载parsing。 所以,在这两种情况下,重载分辨率都selectfoo(T*)
。 但是,只有在第一种情况下才会findfoo<int*>(int*)
因为在第二种情况下, int*
是foo(T)
,而不是foo(T*)
。
你提到了std::swap
。 这使事情变得更加复杂。
该标准说,你可以添加特化到std
命名空间。 太好了,所以你有一些Foo
types,它有一个高性能的交换,那么你只需要在std
命名空间中专门swap(Foo&, Foo&)
。 没问题。
但是,如果Foo
是一个模板类呢? C ++没有部分function的专业化,所以你不能专注于swap
。 你唯一的select是重载,但是标准说你不允许在std
命名空间中添加重载。
在这一点上你有两个select:
-
在你自己的命名空间中创build一个
swap(Foo<T>&, Foo<T>&)
函数,并希望通过ADLfind它。 我说“希望”,因为如果标准库调用交换像std::swap(a, b);
那么ADL根本行不通。 -
忽略标准中说不要添加重载的部分,并且无论如何都要这样做。 老实说,即使在技术上是不允许的,在所有现实的情况下,它都会起作用。
要记住的一件事是,不能保证标准库完全使用swap
。 大多数algorithm使用std::iter_swap
,在我看过的一些实现中,它并不总是转发到std::swap
。
彼得·亚历山大的答案几乎没有增加。 让我仅仅提到一个使用这个特殊function的应用程序可能比overloading更好:如果你必须在没有参数的函数中进行select 。
例如
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; }
你不能在std
命名空间中重载函数,但是你可以专门化模板(我记得),所以这是一个选项。
另一个select是把你的swap
函数放在和它一样的命名空间中,并using std::swap;
在调用不合格的交换之前。