如何有效地在向量中插入多个可复制构造但不可复制分配的元素?

我有一个类型X,它是可复制构造但不可复制分配的

struct X {
    X();
    X(const X&);
    X& operator=(const X&) = delete; // !!
    X(X&&) noexcept;
    X& operator=(X&&) noexcept;
    int data = 54;
};

我有“X”两个向量:ab我想插入的所有内容b在前面a

void add_to_front(std::vector<X>& a, const std::vector<X>& b) {
    a.insert(a.begin(), b.begin(), b.end());
}

这在 msvc 上编译并按预期工作,但无法在 clang 和 gcc 上编译。我猜是由于 libc++ 和 libstdc++ 的糟糕实现,即使它永远不会被调用(或者,更糟糕的是,它会被调用!?),它们需要一些东西来编译。

我可以写一本手册回路emplace的元素b进入a,这将产生一个正确的结果,但这样的复杂性是A * B,而不是A + B,因为每次调用emplace将转移的所有元素a一遍又一遍。

那么有没有有效的方法呢?

现场演示可以在这里找到

回答

我必须承认,我不太确定libc++ 和 libstdc++糟糕实现是否是问题所在。不过,我找到了一种非常简单的方法来规避 OP 问题:

#include <vector>

struct X {
    X() = default;
    X(const X&) = default;
    X& operator=(const X&) = delete; // !!
    X(X&&) noexcept = default;
    X& operator=(X&&) noexcept = default;
    int data = 54;
};

void add_to_front(std::vector<X>& a, const std::vector<X>& b) {
    std::vector<X> b_(b);
    a.insert(a.begin(), std::make_move_iterator(b_.begin()), std::make_move_iterator(b_.end()));
}

int main()
{
  std::vector<X> a, b;
  add_to_front(a, b);
}

这被接受

  • 叮当 11.0.0 -std=c++11 -O2
  • 海湾合作委员会 9.2 -std=c++11 -O2
  • msvc 19.28 /std:c++14 /O2

Compiler Explorer 上的实时演示


@Evg查看了 std::vector::insert()
类型要求

在 OP 的情况下,这是超载:

template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );

  • T 必须满足 EmplaceConstructible 的要求才能使用重载 (4,5)。
  • T 必须满足 MoveAssignable 和 MoveInsertable 的要求才能使用重载 (4)。仅当 InputIt 满足 LegacyInputIterator 但不满足 LegacyForwardIterator 时才需要。

这应该由 OP 授予struct X

所以,对我来说,看起来 OP 对投诉是正确的。

  • I reported at llvm's bug tracker: https://bugs.llvm.org/show_bug.cgi?id=48619

以上是如何有效地在向量中插入多个可复制构造但不可复制分配的元素?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>