向量<unique_ptr<A>>使用初始化列表 [英] vector<unique_ptr<A> > using initialization list

查看:28
本文介绍了向量<unique_ptr<A>>使用初始化列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个错误:在编译类似于下面的代码时调用'std::__1::unique_ptr >'的隐式删除的复制构造函数c++ -std=c++14 unique_ptr_vector.cpp -o main

这是一个简化版:

头文件'my_header.h':

header file 'my_header.h':

#include <iostream>
#include <string>
#include <memory>
#include <vector>

class A{
public:
    A() : n(0) {}
    A(int val) : n(val) {} 
    A(const A &rhs): n(rhs.n) {}
    A(A &&rhs) : n(std::move(rhs.n)) {}
    A& operator=(const A &rhs) { n = rhs.n; return *this; }
    A& operator=(A &&rhs) { n = std::move(rhs.n); return *this; }
    ~A() {}

    void print() const { std::cout << "class A: " << n << std::endl; }
private:
    int n;
};

namespace {
    std::vector<std::unique_ptr<A>> vecA = {
        std::make_unique<A>(1),
        std::make_unique<A>(2),
        std::make_unique<A>(3),
        std::make_unique<A>(4)
    };
}

还有我的src文件unique_ptr_vector.cpp:

#include "my_header.h"

using namespace std;

int main()
{
    for(const auto &ptrA : vecA){
        ptrA->print();
    }
    return 0;
}

我真的需要为每个组件单独使用 push_back(std::make_unique<A>(<some_number>)),或者在标题中填充容器的首选方法是什么?还是一般来说这是个坏主意?

Do I really need to use push_back(std::make_unique<A>(<some_number>)) individually for each component, Or what would be a preferred way to populate a container in a header? Or is this a bad idea in general?

我看到了类似 这个这个这个.

I have seen problems around like this one, this one, and this one.

我现在知道初始化列表似乎是不可能的.但是人们通常用 container<unique_ptr> 做什么.我是否应该简单地避免在标题中初始化它...

I know now Initialization list seems impossible. but what do people normally do with container<unique_ptr>. Should I just simply avoid initialize that in a header...

推荐答案

初始化列表是 const 数组的包装器.

Initialization lists are wrappers around const arrays.

unique_ptrs 是 const 不能被移出.

unique_ptrs that are const cannot be moved-from.

我们可以像这样(以完全合法的方式)解决这个问题:

We can hack around this (in a perfectly legal way) like this:

template<class T>
struct movable_il {
  mutable T t;
  operator T() const&& { return std::move(t); }
  movable_il( T&& in ): t(std::move(in)) {}
};

template<class T, class A=std::allocator<T>>
std::vector<T,A> vector_from_il( std::initializer_list< movable_il<T> > il ) {
  std::vector<T,A> r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

活生生的例子.

用途:

auto v = vector_from_il< std::unique_ptr<int> >({
  std::make_unique<int>(7), 
  std::make_unique<int>(3)
});

如果您想知道为什么初始化程序列表引用 const 数据,您必须追踪并阅读委员会会议记录或询问在场的人.我猜这是关于最小惊喜的原则和/或人们对可变数据和视图类型的错误(例如将 array_view 重命名为 span).

If you want to know why initializer lists reference const data, you'll have to track down and read committee minutes or ask someone who was there. I'd guess it is about the principle of least surprise and/or people with bugaboos about mutable data and view types (such as the renaming of array_view to span).

如果您想要的不仅仅是向量:

If you want more than just vectors:

template<class C, class T=typename C::value_type>
C container_from_il( std::initializer_list< movable_il<T> > il ) {
  C r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

这仍然需要按摩才能与关联容器一起正常工作,因为我们还想移动键.

which still needs massaging to work right with associative containers as we also want to move the key.

template<class VT>
struct fix_vt {
  using type=VT;
};
template<class VT>
using fix_vt_t = typename fix_vt<VT>::type;
template<class VT>
struct fix_vt<const VT>:fix_vt<VT>{};
template<class K, class V>
struct fix_vt<std::pair<K,V>>{
  using type=std::pair<
    typename std::remove_cv<K>::type,
    typename std::remove_cv<V>::type
  >;
};

template<class C, class T=fix_vt_t<typename C::value_type>>
C container_from_il( std::initializer_list< movable_il<T> > il ) {
  C r( std::make_move_iterator(il.begin()), std::make_move_iterator(il.end()) );
  return r;
}

这篇关于向量&lt;unique_ptr&lt;A&gt;&gt;使用初始化列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆