c++ 为什么std::swap不交换std::reference_wrapper的底层对象?

6ju8rftf  于 2023-05-02  发布在  其他
关注(0)|答案(2)|浏览(108)

背景:

我正在尝试实现一个函数,让我们称之为mysort,它接受相同类型的可变数量的参数并对其进行排序。例如,下面的代码应该打印1 2 3

template <typename ... Args>
void mysort(Args& ... args);
int main(int, char**)
{
    int x = 3;
    int y = 1;
    int z = 2;
    mysort(x, y, z);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

我尝试过的:

下面是我想出的解决方案

#include <array>
#include <algorithm>
#include <functional>

template <typename T, typename ... Args>
void mysort(T& t, Args& ... args)
{
    constexpr size_t n = sizeof...(Args) + 1;
    std::array<std::reference_wrapper<T>, n> temp = { std::ref(t), std::ref(args)... };
    std::sort(temp.begin(), temp.end());
}

但是这个解决方案不起作用,因为std::swapstd::reference_wrapper所做的不是我所期望的(我期望对std::reference_wrapper的任何更改都应该更改为其创建std::reference_wrapper的对象)。
adding之后,一切都开始工作

namespace std
{
    void swap(std::reference_wrapper<int>& a, std::reference_wrapper<int>& b) noexcept
    {
        std::swap(a.get(), b.get());
    }
}

我不确定标准是否要求std::sort使用std::swap,所以我认为这不是一个完整的解决方案,并且依赖于实现。

汇总:

我对std::reference_wrapper的想法是,它应该像引用一样工作,但情况似乎并非如此。以下是我的问题:
1.什么是实现mysort的最佳方法?
1.为什么标准没有为std::reference_wrapper提供交换底层对象的std::swap规范?
提前感谢您的回答!

ztyzrc3y

ztyzrc3y1#

std::reference_wrapper的要点是它是可复制和可赋值的,“可赋值”的意思是引用 Package 器可以以普通引用不能的方式反弹到新值。
你在做与它的本意相反的事情。在您的例子中,当std::sort的实现交换临时数组中的项时,它重新绑定了引用,但这不是您想要的。您希望它交换实际的项而不是引用。
一种方法是让std::sort对参数的副本进行排序,然后将它们按排序顺序分配回引用参数:

template <typename T, typename ... Args>
void mysort(T& t, Args& ... args)
{
    constexpr size_t n = sizeof...(Args) + 1;
    std::array<T, n> temp = { t, args... };
    std::sort(temp.begin(), temp.end());
    std::tie(t, args...) = std::tuple_cat(temp);
}

在这里,我将它们 Package 在一个元组中,以便可以通过std::tie进行赋值。可能有一些方法可以用更少的副本来做到这一点,但这是我想到的。

5sxhfpxr

5sxhfpxr2#

基本上,std::reference_wrapper是一个旧的设计不佳的类,目前用于某些简单的目的,如在std::bind/bind_frontstd::thread的构造中,它用于暗示变量不是复制的,而是通过引用获取的。然后通过std::ref/cref创建它们。
我只是不建议使用std::reference_wrapper,除了模板情况下,它用于区分用户是想要转发对象的副本还是引用。
如果你想要一个模仿引用的类来执行赋值/移动,而不是重新绑定,那就由你来实现了。只是你应该意识到在某些情况下可能会有问题。
也不要写任何

namespace std
{
    void swap(std::reference_wrapper<int>& a, std::reference_wrapper<int>& b) noexcept
    {
        std::swap(a.get(), b.get());
    }
}

它可能会破坏您导入的大量代码。

相关问题