C++ 如何为我的班级提供交换功能?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6380862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to provide a swap function for my class?
提问by pic11
What is the proper way to enable my swap
in STL algorithms?
swap
在 STL 算法中启用我的正确方法是什么?
1) Member swap
. Does std::swap
use SFINAE trick to use the member swap
.
1) 会员swap
。是否std::swap
使用 SFINAE 技巧使用会员swap
。
2) Free standing swap
in the same namespace.
2) 独立swap
于同一命名空间。
3) Partial specialization of std::swap
.
3) 的部分专业化std::swap
。
4) All of the above.
4)以上所有。
Thank you.
谢谢你。
EDIT: Looks like I didn't word my question clearly. Basically, I have a template class and I need STL algos to use the (efficient) swap method I wrote for that class.
编辑:看起来我没有清楚地表达我的问题。基本上,我有一个模板类,我需要 STL 算法来使用我为该类编写的(高效)交换方法。
回答by Xeo
1) is the proper useof swap
. Write it this way when you write "library" code and want to enable ADL (argument-dependent lookup) on swap
. Also, this has nothing to do with SFINAE.
1)是正确使用的swap
。当您编写“库”代码并希望在swap
. 此外,这与 SFINAE 无关。
// some algorithm in your code
template<class T>
void foo(T& lhs, T& rhs){
using std::swap; // enable 'std::swap' to be found
// if no other 'swap' is found through ADL
// some code ...
swap(lhs, rhs); // unqualified call, uses ADL and finds a fitting 'swap'
// or falls back on 'std::swap'
// more code ...
}
2) Is the proper way to provide a swap
function for your class.
2) 是swap
为您的班级提供功能的正确方法。
namespace Foo{
class Bar{}; // dummy
void swap(Bar& lhs, Bar& rhs){
// ...
}
}
If swap
is now used as shown in 1), your function will be found. Also, you may make that function a friend if you absolutely need to, or provide a member swap
that is called by the free function:
如果swap
现在按 1) 所示使用,将找到您的函数。此外,如果您绝对需要,您可以将该函数设为好友,或者提供一个swap
由 free 函数调用的成员:
// version 1
class Bar{
public:
friend void swap(Bar& lhs, Bar& rhs){
// ....
}
};
// version 2
class Bar{
public:
void swap(Bar& other){
// ...
}
};
void swap(Bar& lhs, Bar& rhs){
lhs.swap(rhs);
}
3) You mean an explicit specialization. Partial is still something else and also not possible for functions, only structs / classes. As such, since you can't specialize std::swap
for template classes, you haveto provide a free function in your namespace. Not a bad thing, if I may say so. Now, an explicit specialization is also possible, but generally you do not want to specialize a function template:
3)你的意思是明确的专业化。Partial 仍然是别的东西,对于函数也不可能,只有结构/类。因此,由于您不能专门std::swap
用于模板类,您必须在您的命名空间中提供一个免费函数。不是坏事,如果我可以这么说。现在,显式特化也是可能的,但通常您不想特化函数模板:
namespace std
{ // only allowed to extend namespace std with specializations
template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs){
// ...
}
}
4) No, as 1) is distinct from 2) and 3). Also, having both 2) and 3) will lead to always having 2) picked, because it fits better.
4) 否,因为 1) 不同于 2) 和 3)。此外,同时拥有 2) 和 3) 将导致始终选择 2),因为它更适合。
回答by Ben
To answer the EDIT, where the classes may be template classes, you don't need specialization at all. consider a class like this:
要回答编辑,其中类可能是模板类,您根本不需要专业化。考虑这样一个类:
template <class T>
struct vec3
{
T x,y,z;
};
you may define classes such as:
您可以定义类,例如:
vec3<float> a;
vec3<double> b;
vec3<int> c;
if you want to be able to create one function to implement all 3 swaps (not that this example class warrants it) you do just like Xeo said in (2)... without specialization but just make a regular template function:
如果你希望能够创建一个函数来实现所有 3 个交换(不是这个示例类保证它)你就像 Xeo 在(2)中所说的那样......没有专门化,只是制作一个常规模板函数:
template <class T>
void swap(vec3<T> &a, vec3<T> &b)
{
using std::swap;
swap(a.x,b.x);
swap(a.y,b.y);
swap(a.z,b.z);
}
The swap template function should be located in the same namespace as the class you're trying to swap. the following method will find and use that swap even though you're not referencing that namespace using ADL:
交换模板函数应位于与您尝试交换的类相同的命名空间中。即使您没有使用 ADL 引用该命名空间,以下方法也会找到并使用该交换:
using std::swap;
swap(a,b);
回答by anton_rh
It seems that (2) (free standing swap
in the same namespace where the user-defined class is declared) is the only allowed way to provide swap
for a user-defined class, because adding declarations to namespace std
is generally an undefined behavior. Extending the namespace std (cppreference.com):
似乎 (2)(在声明用户定义类的同一命名空间中独立存在swap
)是提供swap
用户定义类的唯一允许方式,因为向命名空间添加声明std
通常是未定义的行为。扩展命名空间 std (cppreference.com):
It is undefined behavior to add declarations or definitions to namespace
std
or to any namespace nested withinstd
, with a few exceptions noted below
将声明或定义添加到命名空间
std
或嵌套在 中的任何命名空间是未定义的行为,std
下面指出了一些例外
And swap
is not denoted as one of those exceptions. So adding your own swap
overload to the std
namespace is an undefined behavior.
并且swap
不表示为这些例外之一。因此,将您自己的swap
重载添加到std
命名空间是一种未定义的行为。
It's also said that the standard library uses an unqualified call to the swap
function in order to call user-defined swap
for a user class if such user-defined swap
is provided.
也有人说,如果提供了这样的用户定义,标准库使用对swap
函数的非限定调用,以便swap
为用户类调用用户定义swap
。
Many standard library functions (for example, many algorithms) expect their arguments to satisfy Swappable, which means that any time the standard library performs a swap, it uses the equivalent of
using std::swap; swap(t, u);
.
许多标准库函数(例如,许多算法)期望它们的参数满足Swappable,这意味着任何时候标准库执行交换,它使用等效的
using std::swap; swap(t, u);
。
Many components of the standard library (within
std
) callswap
in an unqualifiedmanner to allow custom overloads for non-fundamental types to be called instead of this generic version: Custom overloads ofswap
declared in the same namespace as the type for which they are provided get selected through argument-dependent lookupover this generic version.
标准库(内
std
)的许多组件swap
以非限定方式调用,以允许调用非基本类型的自定义重载而不是这个通用版本:swap
在与提供它们的类型相同的命名空间中声明的自定义重载被选中通过对这个通用版本的参数依赖查找。
But note that directly using the std::swap
function for a user-defined class calls the generic version of std::swap
instead of the user-defined swap
:
但请注意,直接将std::swap
函数用于用户定义的类调用的是通用版本std::swap
而不是用户定义的swap
:
my::object a, b;
std::swap(a, b); // calls std::swap, not my::swap
So it is recommended to call the swap
function in user code in the same way as it is done in the standard library:
所以建议swap
在用户代码中调用该函数的方式与在标准库中的调用方式相同:
my::object a, b;
using std::swap;
swap(a, b); // calls my::swap if it is defined, or std::swap if it is not.