如何为我的班级提供交换功能?

发布于 2024-11-16 03:17:58 字数 314 浏览 2 评论 0原文

在 STL 算法中启用交换的正确方法是什么?

1) 会员交换std::swap 是否使用 SFINAE 技巧来使用成员 swap

2) 在同一命名空间中独立的交换

3) std::swap 的部分特化。

4)以上所有。

谢谢。

编辑:看来我没有清楚地表达我的问题。基本上,我有一个模板类,我需要 STL 算法来使用我为该类编写的(高效)交换方法。

What is the proper way to enable my swap in STL algorithms?

1) Member swap. Does std::swap use SFINAE trick to use the member swap.

2) Free standing swap in the same namespace.

3) Partial specialization of std::swap.

4) All of the above.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

安人多梦 2024-11-23 03:17:58
  1. 交换的正确使用。当您编写“库”代码并希望在 swap 上启用 ADL(参数相关查找)时,可以这样编写。另外,这与 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 ...
}
  1. 以下是为您的类提供 swap 函数的正确方法:
namespace Foo {

class Bar{}; // dummy

void swap(Bar& lhs, Bar& rhs) {
    // ...
}

}

如果现在使用 swap,如 1) 所示,您的函数将被找到。另外,如果您绝对需要,您可以将该函数设为友元,或者提供由自由函数调用的成员 swap

// 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);
}

...
  1. 您的意思是显式专业化。部分仍然是其他东西,对于函数也是不可能的,只能是结构/类。因此,由于您无法将 std::swap 专门用于模板类,因此您必须在命名空间中提供一个自由函数。如果我可以这么说的话,这并不是一件坏事。现在,显式专门化也是可能的,但通常您不想专门化函数模板
namespace std
{  // only allowed to extend namespace std with specializations

template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
    // ...
}

}
  1. 否,因为 1) 不同于 2) 和 3)。此外,同时拥有 2) 和 3) 将导致始终选择 2),因为它更适合。
  1. is the proper use of 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.
// 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 ...
}
  1. Here is the proper way to provide a swap function for your class:
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:

// 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);
}

...
  1. 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 have to 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:
namespace std
{  // only allowed to extend namespace std with specializations

template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
    // ...
}

}
  1. 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.
百变从容 2024-11-23 03:17:58

似乎 (2)(在声明用户定义类的同一命名空间中独立的交换)是唯一允许提供交换的方式 code> 对于用户定义的类,因为向命名空间 std 添加声明通常是未定义的行为。 扩展命名空间 std (cppreference.com)

向命名空间 std 或嵌套在 std 中的任何命名空间添加声明或定义是未定义的行为,下面列出了一些例外情况

,并且 swap 是未表示为这些例外之一。因此,将您自己的 swap 重载添加到 std 命名空间是一种未定义的行为。

还据说标准库使用对 swap 函数的非限定调用,以便为用户类调用用户定义的 swap(如果此类用户定义的 swap)提供了。

可交换 (cppreference.com)

许多标准库函数(例如,许多算法)期望它们的参数满足 Swappable,这意味着标准库每次执行交换时,它都会使用 using std 的等效项::交换;交换(t,u);

交换 (www.cplusplus.com)

标准库的许多组件(在 std 内)以非限定方式调用 swap,以允许非基本类型的自定义重载被调用而不是这个通用版本:在与提供它们的类型相同的命名空间中声明的 swap 的自定义重载通过在此通用版本上的依赖于参数的查找来选择.

但请注意,直接对用户定义的类使用 std::swap 函数会调用 std::swap 的通用版本,而不是用户定义的 swap

my::object a, b;
std::swap(a, b); // calls std::swap, not my::swap

因此建议在用户代码中以与标准库中相同的方式调用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.

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):

It is undefined behavior to add declarations or definitions to namespace std or to any namespace nested within std, with a few exceptions noted below

And swap is not denoted as one of those exceptions. So adding your own swap overload to the std namespace is an undefined behavior.

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.

Swappable (cppreference.com):

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

swap (www.cplusplus.com):

Many components of the standard library (within std) call swap in an unqualified manner to allow custom overloads for non-fundamental types to be called instead of this generic version: Custom overloads of swap declared in the same namespace as the type for which they are provided get selected through argument-dependent lookup over this generic version.

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:

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:

my::object a, b;
using std::swap;
swap(a, b); // calls my::swap if it is defined, or std::swap if it is not.
提赋 2024-11-23 03:17:58

要回答编辑,其中类可能是模板类,您根本不需要专门化。考虑这样一个类:

template <class T>
struct vec3
{
    T x,y,z;
};

您可以定义这样的类:

vec3<float> a;
vec3<double> b;
vec3<int> c;

如果您希望能够创建一个函数来实现所有 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);
}

交换模板函数应位于与您要交换的类相同的命名空间中。即使您没有使用 ADL 引用该命名空间,以下方法也将找到并使用该交换:

using std::swap;
swap(a,b);

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:

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:

using std::swap;
swap(a,b);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文