数据成员和常量的make_move_iterator:如何使其失败?

make_move_iterator for data member and const: how make it failed?

提问人:user1244932 提问时间:11/9/2023 最后编辑:user1244932 更新时间:11/9/2023 访问量:54

问:

下面是示例:

#include <vector>
#include <iterator>

class Foo {
public:
  void combine(std::vector<std::vector<float>> &all_data) const {
    all_data.insert(all_data.end(), std::make_move_iterator(data_.begin()),
            std::make_move_iterator(data_.end()));
  }
private:
  std::vector<std::vector<float>> data_;
};

问题是它在没有任何警告的情况下编译, 而 + 应该 在我看来失败了。conststd::make_move_iterator(not_volatile_data_member)

为什么不是编译时错误,将来如何防止此类错误?

编辑:

如果无法移动数据成员()中的数据,并且我得到复制而不是移动,则我想要编译错误,而我明确告诉编译器我想要移动。data_make_move_iterator

C++ STL C++17

评论

3赞 463035818_is_not_an_ai 11/9/2023
当无法移动内容时,移动通常会回退到副本。
0赞 463035818_is_not_an_ai 11/9/2023
".....除了取消引用将基础迭代器返回的值转换为右值。如果将此迭代器用作输入迭代器,则效果是将值移出,而不是从中复制。(en.cppreference.com/w/cpp/iterator/move_iterator) 没有理由这样做
4赞 Weijun Zhou 11/9/2023
迭代器部分是无关紧要的。如果以类似的方式使用,也会发生同样的情况。 如果是,则简单地复制 .std::movea=std::move(b)bbconst
0赞 463035818_is_not_an_ai 11/9/2023
根据您的推理,这也应该是一个错误,但完全没问题const int x = 42; std::move(x);
0赞 Weijun Zhou 11/9/2023
此外,通常在编译时无法检测到此类内容。对于类型,可以检测到该类型是仅移动类型,但无法检测到同时具有复制和移动构造函数但行为不同的类型。复制和移动分配运算符也是如此。TTT

答:

1赞 Weijun Zhou #1

如果你真的想这样做,并且只想检测问题。这可以通过添加您自己的包装器来实现。const

#include <vector>
#include <iterator>

template <typename Iter>
decltype(auto) my_make_move_iterator(Iter&& it){
    static_assert(!std::is_const_v<std::remove_reference_t<decltype(*it)>>);
    return std::make_move_iterator(std::forward<Iter>(it));
}

class Foo {
public:
  void combine(std::vector<std::vector<float>> &all_data) const {
    all_data.insert(all_data.end(), my_make_move_iterator(data_.begin()),
            my_make_move_iterator(data_.end()));
  }
private:
  std::vector<std::vector<float>> data_;
};

但是,我强烈反对这样做,因为它不能防止许多其他类似的常见错误,并且还会使代码对碰巧阅读您的代码的其他人更加困惑。