【问题标题】:Can I sort vector of tuple of references?我可以对引用元组的向量进行排序吗?
【发布时间】:2016-05-10 15:12:51
【问题描述】:

以下代码时:

std::vector<std::tuple<int&>> v;
int a = 5; v.emplace_back(a);
int b = 4; v.emplace_back(b);
int c = 3; v.emplace_back(c);
int d = 2; v.emplace_back(d);
int e = 1; v.emplace_back(e);
std::sort(std::begin(v), std::end(v));

使用 gcc/libstdc++ 编译 vs clang/libc++ 二进制给出不同的结果。

对于gcc/libstdc++,一个元素被复制到所有其他引用。

5 4 3 2 1 
5 5 5 5 5

首先我认为clang/libc++ 的行为符合预期,但它最多只能在一个向量中使用 5 个元素(因为小容器有一种特殊情况)。

5 4 3 2 1 
1 2 3 4 5 

当传递更多元素时,结果类似于 gcc。

5 4 3 2 1 0 
3 4 5 5 5 5

那么将std::sort 用于具有引用的元组容器(即使用std::tie,结构的排序子集)是否有效? 如果没有,我应该期待任何警告吗?

【问题讨论】:

    标签: sorting c++11 tuples


    【解决方案1】:

    那么将std::sort 用于具有引用的元组容器(即使用std::tie,结构的排序子集)是否有效?如果没有,我应该期待任何警告吗?

    没有,也没有。 std::sort() 的类型要求之一是:

    • 取消引用的RandomIt的类型必须满足MoveAssignableMoveConstructible的要求。

    其中MoveAssignable 需要在表达式t = rv 中:

    t 的值等价于分配前rv 的值。

    但是 std::tuple&lt;int&amp;&gt; 不是 MoveAssignable,因为 int&amp; 不是 MoveAssignable。如果你有:

    int& ra = a;
    int& rb = b;
    
    ra = std::move(rb);
    

    ra 的值不等于 rb 的先前值。 ra 仍然引用 a,它并没有改变引用b - 实际上改变的是a 的值。

    由于我们的类型不满足std::sort() 的前提条件,std::sort() 调用的结果只是未定义的行为。


    请注意,您可以std::vector&lt;std::tuple&lt;std::reference_wrapper&lt;int&gt;&gt;&gt; 进行排序,因为std::reference_wrapper 是MoveAssignable。

    另请注意,这让人想起无法对 auto_ptr 的容器进行分类,根据老 Herb Sutter article

    【讨论】:

    • 使用std::reference_wrapper&lt;int&gt; 有效,因为它可以从std::tie 构造,但需要一些模板魔法来获取T&...类型列表并用reference_wrapper 装饰它。 Both compilers 同意 std::tuple&lt;int&amp;&gt; is_move_assignable && is_move_constructible(具有标准特征)
    • @KarolWozniak 该特征只能检查实际语义是否有效——您可以移动分配tuple&lt;int&amp;&gt;。它只是没有该操作需要具有的实际行为才能被视为 MoveAssignable。
    • @KarolWozniak 例如,struct X { int val; X&amp; operator=(X&amp;&amp; ) { return *this; }; is_move_assignable&lt;X&gt; 为真,但 X 实际上不是 MoveAssignable,因为未满足要求。
    • 我可以考虑用my_own::tie_wrapper替换std::tie,这样可以优雅地解决我原来的问题,谢谢!
    猜你喜欢
    • 2018-10-31
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 2013-05-31
    • 2018-06-19
    • 2022-08-16
    相关资源
    最近更新 更多