简体   繁体   English

模板专业化 VS Function 重载

[英]Template Specialization VS Function Overloading

A textbook I have notes that you can provide your own implementation for standard library functions like swap(x,y) via template specialization or function overloading.一本教科书我注意到您可以通过模板专业化或 function 重载为标准库函数(如swap(x,y)提供自己的实现。 This would be useful for any types which can benefit from something other than an assignment swap, like STL containers for example (which already have swaps written, I know).这对于任何可以从分配交换以外的东西中受益的类型都很有用,例如 STL 容器(我知道,它已经编写了交换)。

My questions are the following:我的问题如下:

  1. What's better: template specialization to give your specialized swap implementation, or function overloading providing the exact parameters you wish to use without a template?更好的是:模板专业化为您提供专门的交换实现,或 function 重载提供您希望在没有模板的情况下使用的确切参数?

  2. Why is it better?为什么更好? Or if they're equal, why is this?或者如果他们是平等的,这是为什么呢?

Short story: overload when you can, specialise when you need to.简短的故事:在你可以的时候超负荷,在你需要的时候专注。

Long story: C++ treats specialisation and overloads very differently.长话短说:C++ 以非常不同的方式对待特化和重载。 This is best explained with an example.这最好用一个例子来解释。

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*);

Now let's swap the last two.现在让我们交换最后两个。

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*) !!!

The compiler does overload resolution before it even looks at specialisations.编译器甚至在查看特化之前就进行重载解析。 So, in both cases, overload resolution chooses foo(T*) .因此,在这两种情况下,重载决议都选择foo(T*) However, only in the first case does it find foo<int*>(int*) because in the second case the int* specialisation is a specialisation of foo(T) , not foo(T*) .然而,只有在第一种情况下它才会找到foo<int*>(int*)因为在第二种情况下int*foo(T) ,而不是foo(T*)


You mentioned std::swap .你提到了std::swap This makes things even more complicated.这让事情变得更加复杂。

The standard says that you can add specialisations to the std namespace.该标准说您可以向std命名空间添加专业化。 Great, so you have some Foo type and it has a performant swap then you just specialise swap(Foo&, Foo&) in the std namespace.太好了,所以你有一些Foo类型,它有一个高性能的交换,那么你只需在std命名空间中专门化swap(Foo&, Foo&) No problems.没问题。

But what if Foo is a template class?但是如果Foo是一个模板类呢? C++ doesn't have partial specialisation of functions, so you can't specialise swap . C++ 没有函数的部分特化,所以你不能特化swap Your only choice is overloading, but the standard says that you aren't allowed to add overloads into the std namespace!你唯一的选择是重载,但标准说你不能在std命名空间中添加重载!

You have two options at this point:此时您有两个选择:

  1. Create a swap(Foo<T>&, Foo<T>&) function in your own namespace, and hope that it gets found via ADL.在您自己的命名空间中创建一个swap(Foo<T>&, Foo<T>&)函数,并希望通过 ADL 找到它。 I say "hope" because if the standard library calls swap like std::swap(a, b);我说“希望”是因为如果标准库像std::swap(a, b);一样调用 swap std::swap(a, b); then ADL simply won't work.那么 ADL 根本就行不通。

  2. Ignore the part of the standard that says not to add overloads and do it anyway.忽略标准中说不要添加重载的部分,无论如何都要这样做。 Honestly, even though it's technically not allowed, in all realistic scenarios it's going to work.老实说,即使技术上不允许,但在所有现实场景中它都会起作用。

One thing to remember though is that there's no guarantee that the standard library uses swap at all.但要记住的一件事是,不能保证标准库完全使用swap Most algorithms use std::iter_swap and in some implementations that I've looked at, it doesn't always forward to std::swap .大多数算法使用std::iter_swap ,在我看过的一些实现中,它并不总是转发到std::swap

There's little to add to Peter Alexander's answer.彼得亚历山大的回答几乎没有什么可补充的。 Let me just mention one use in wich function specialization could be prefearable over overloading: if you have to select among functions with no parameters .让我只提一个用途,其中函数专业化可能比重载更可取:如果您必须在没有参数的函数中进行选择

Eg例如

template<class T> T zero();
template<> int zero() { return 0; }
template<> long zero() { return 0L; }

To do something similar using function overloading, you would have to add a parameter to the function signature:要使用函数重载做类似的事情,你必须在函数签名中添加一个参数:

int zero(int) { return 0; }
long zero(long) { return 0L; }

You aren't allowed to overload functions in the std namespace, but you are allowed to specialize templates (as I recall), so that's one option.不允许重载std命名空间中的函数,但允许专门化模板(我记得),所以这是一种选择。

The other option is to put your swap function in the same namespace as the thing it's operating on and using std::swap;另一种选择是将您的swap函数放在与其操作的事物相同的命名空间中并using std::swap; before calling an unqualified swap.在调用不合格的交换之前。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM