是否有一种很好的方法可以将STD :: Minmax(A,B)分配给STD :: TIE(A,B)

Is there a nice way to assign std::minmax(a, b) to std::tie(a, b)?

本文关键字:STD 分配 TIE Minmax 一种 很好 是否 方法      更新时间:2023-10-16
std::tie(a, b) = std::minmax(a, b);

我认为这是直观的代码。干净和可理解。太糟糕了,它无法正常工作,就像std::minmax模板const&一样。因此,如果值交换在std::pair<const&, const&>内,则与一个分配相比将覆盖另一个值:

auto[a, b] = std::make_pair(7, 5);
std::tie(a, b) = std::minmax(a, b);
std::cout << "a: " << a << ", b: " << b << 'n';

a:5,b:5

这里的预期输出是a: 5, b: 7


我认为这很重要,因为实施转换功能以将功能应用于某些范围需要直观的lambdas陈述。例如:

std::vector<int> v{ 0, 1, 0, 2, 0 };
std::vector<int> u{ 1, 0, 1, 0, 1 };
perform(v.begin(), v.end(), u.begin(), [](auto& a, auto& b){ 
    std::tie(a, b) = std::minmax(a, b);    
}); 
//v would be == {0, 0, 0, 0, 0}
//u would be == {1, 1, 1, 2, 1}

我发现的一种解决方案是在std::pair<const&, const&>上明确构建std::tuple,没有任何参考预选赛来强制执行副本:

std::tie(a, b) = std::tuple<int, int>(std::minmax(a, b)); 

但是,这种<int, int>冗余似乎很糟糕,尤其是在以前说过auto& a, auto& b时。


是否有一个很好的方法可以执行此任务?难道这是错误的方向,只是说if (a >= b) { std::swap(a, b); }是这里最好的方法吗?

您可以使用 minmax的初始化列表:

std::tie(a, b) = std::minmax({a, b});

这会导致创建临时对象,就像使用 unary plus 时一样,但它的好处是它与缺少 Unary plus plus 操作员的类型一起工作。

using namespace std::string_view_literals;
auto [a, b] = std::make_pair("foo"sv, "bar"sv);
std::tie(a, b) = std::minmax({a, b});
std::cout << "a: " << a << ", b: " << b << 'n';

输出:

a: bar, b: foo

这可能是错误的方向,只是说if (a >= b) { std::swap(a, b); }是这里最好的方法吗?

由于比较 1 要求,我会将其制作if(b < a) std::swap(a, b);,但是,是的,我怀疑这会更快,而且仍然很清楚您想完成的工作。


[1] 比较[...]应用于对象的函数调用操作的返回值 令人满意的类型比较,当上下文转换为布尔时, 如果呼叫的第一个参数出现在 第二类是由这种类型引起的严格弱排序关系,以及 否否则。

您可以用以下一定级别的简短执行此操作。

std::tie(a, b) = std::minmax(+a, +b);
std::cout << "a: " << a << ", b: " << b << 'n';

说明:为了对称性,内置的Unary Plus运算符与其单位减兄弟姐妹,通过Value 返回其操作数(它也执行通常的算术转换,但这不适用于int s(。这意味着它必须创建一个临时性,即使此临时性不过是操作数的副本。但是对于在此示例中使用minmax,这已经足够了:此处的交换引用不再通过,因为右侧的引用(const int&参数传递给了minmax(不参考与在左侧(std::tie创建的参考文献的tuple(。

输出是根据需要的:

a:5,b:7

有时候,退后一步,找到另一种方式回报:

if (b < a)
    std::iter_swap(&a, &b);

这很简洁,通常更有效,至少在标准杆上。也许将其包装到自己的功能中:

template <class T>
void reorder(T& a, T& b)
noexcept(noexcept(b < a, void(), std::iter_swap(&a, &b))) {
    if (b < a)
        std::iter_swap(&a, &b);
}

我正在使用std::iter_swap(),因此我不必在PRE-C 2A中使用using std::swap; swap(a, b)两步进行通用,该pre-c 2a中引入了自定义点对象,使该对象变得过时。