模板专业化 VS 函数重载
一本教科书我注意到你可以通过模板特化或函数重载为标准库函数提供你自己的实现,比如 swap(x,y)
.这对于任何可以从赋值交换以外的东西中受益的类型都很有用,例如 STL 容器(我知道已经编写了交换).
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. 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).
我的问题如下:
什么更好:模板专业化为您提供专业化交换实现或函数重载提供准确的您希望在没有模板的情况下使用参数?
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?
为什么更好?或者如果它们相等,为什么会这样?
Why is it better? Or if they're equal, why is this?
推荐答案
简短的故事:尽可能超载,在需要时专注.
Short story: overload when you can, specialise when you need to.
长话短说:C++ 对特化和重载的处理非常不同.最好用一个例子来解释这一点.
Long story: C++ treats specialisation and overloads very differently. 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*) !!!
编译器在查看特化之前就进行重载解析.因此,在这两种情况下,重载解析都选择 foo(T*)
.然而,只有在第一种情况下它才找到 foo
因为在第二种情况下 int*
特化是 的特化foo(T)
,不是 foo(T*)
.
The compiler does overload resolution before it even looks at specialisations. So, in both cases, overload resolution chooses 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*)
.
你提到了std::swap
.这让事情变得更加复杂.
You mentioned std::swap
. This makes things even more complicated.
标准规定您可以向 std
命名空间添加专业化.太好了,所以你有一些 Foo
类型并且它有一个高性能的交换然后你只需在 std
中专门化 swap(Foo&, Foo&)
命名空间.没问题.
The standard says that you can add specialisations to the std
namespace. Great, so you have some Foo
type and it has a performant swap then you just specialise swap(Foo&, Foo&)
in the std
namespace. No problems.
但是如果 Foo
是一个模板类呢?C++ 没有函数的部分特化,所以你不能特化swap
.你唯一的选择是重载,但标准规定你不能在 std
命名空间中添加重载!
But what if Foo
is a template class? C++ doesn't have partial specialisation of functions, so you can't specialise swap
. Your only choice is overloading, but the standard says that you aren't allowed to add overloads into the std
namespace!
此时您有两个选择:
在您自己的命名空间中创建一个
swap(Foo<T>&, Foo<T>&)
函数,并希望它可以通过 ADL 找到.我说希望"是因为如果标准库像std::swap(a, b);
一样调用 swap,那么 ADL 根本就行不通.
Create a
swap(Foo<T>&, Foo<T>&)
function in your own namespace, and hope that it gets found via ADL. I say "hope" because if the standard library calls swap likestd::swap(a, b);
then ADL simply won't work.
忽略标准中说不要添加重载的部分,无论如何都要这样做.老实说,即使技术上不允许这样做,但在所有现实场景中它都会起作用.
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.
但要记住的一件事是,标准库根本无法保证使用 swap
.大多数算法使用 std::iter_swap
并且在我看过的一些实现中,它并不总是转发到 std::swap
.
One thing to remember though is that there's no guarantee that the standard library uses swap
at all. Most algorithms use std::iter_swap
and in some implementations that I've looked at, it doesn't always forward to std::swap
.
相关文章