模板专业化VS函数重载

问题描述 投票:49回答:3

一本教科书,我注意到您可以通过模板专用化或函数重载为swap(x,y)等标准库函数提供自己的实现。对于任何可以受益于分配交换以外的东西的类型,这都是很有用的,例如STL containers(我已经知道已经写了交换)。

我的问题如下:

  1. 更好:模板专门化为您提供专门的交换实现或函数重载,以提供确切的信息您希望在没有模板的情况下使用的参数?

  2. 为什么更好?或者,如果它们相等,为什么会这样?

c++ stl template-specialization standard-library overloading
3个回答
69
投票

短篇小说:在可能的情况下超负荷,在需要时进行专业化。

长话短说: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类型,并且具有性能交换,那么您只需在swap(Foo&, Foo&)名称空间中专门设置std。没问题。

但是如果Foo是模板类怎么办? C ++的功能没有部分专业化,因此您不能专业化swap。唯一的选择是重载,但是标准说不允许您将重载添加到std名称空间中!

您目前有两个选择:

  1. 在您自己的名称空间中创建swap(Foo<T>&, Foo<T>&)函数,并希望可以通过ADL找到它。我之所以说“希望”,是因为如果标准库像std::swap(a, b);那样调用swap,那么ADL就根本无法工作。

  2. 忽略标准部分,即不要添加重载,还是要这样做。老实说,即使从技术上讲它是不允许的,但在所有现实情况下它都可以工作。

  3. 不过要记住的一件事是,不能保证标准库完全使用swap。大多数算法都使用std::iter_swap,在我看过的某些实现中,它并不总是转发到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; }

不允许您在std名称空间中重载函数,但是允许您对模板进行专门化(正如我所记得的,所以这是一种选择。

另一种选择是在调用无条件交换之前,将您的swap函数放置在与它正在操作的对象相同的名称空间中,并将using std::swap;放置在同一命名空间中。


13
投票

没有什么可以补充彼得·亚历山大的答案。让我只说一说,如果必须从没有参数的函数中选择


5
投票

不允许您在std名称空间中重载函数,但是允许您对模板进行专门化(正如我所记得的,所以这是一种选择。

© www.soinside.com 2019 - 2024. All rights reserved.