vector<unique_ptr<Base> > 使用 Derived 的初始化列表

vector<unique_ptr<Base> > using initialization list of Derived

我有一个后续问题:

我想实现与引用问题基本相同的目标,但这次使用多态 类。也就是说,我想使用初始化列表创建一个 std::vector<std::unique_ptr<Base>>

#include <vector>
#include <memory>
#include <iterator>
#include <iostream>

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;
}

// Example with class hierarchy
class Base
{
public:
  Base(int in) : x(in) {}
  virtual ~Base() = default;
  virtual void print() const = 0;
protected:
  int x;
};

class Derived1 : public Base
{
public:
  Derived1(int in) : Base(in) {}
  virtual ~Derived1() = default;
  virtual void print() const override { std::cout << "Derived1: " << x << std::endl; }
};

class Derived2 : public Base
{
public:
  Derived2(int in) : Base(in) {}
  virtual ~Derived2() = default;
  virtual void print() const override { std::cout << "Derived2: " << x << std::endl; }
};

int main()
{

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

    for (const auto & val : v)
      val->print();
  }

  return 0;
}

编译器(GCC 7.4.0 on Ubuntu 18)错误消息是:

template argument deduction/substitution failed:
cannot convert '{std::make_unique(_Args&& ...)
[with _Tp = Derived1;
 _Args = {int};
 typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<Derived1, std::default_delete<Derived1> >](),
std::make_unique(_Args&& ...)
[with _Tp = Derived2;
 _Args = {int};
 typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<Derived2, std::default_delete<Derived2> >]()}'
(type '<brace-enclosed initializer list>') to type 'std::initializer_list<movable_il<std::unique_ptr<Base> > >'

我假设这个错误与模板参数推导过程中没有考虑转换有关,所以这可能是不可能的。

添加额外的构造函数

template <typename U>
movable_il(U&& in): t(std::forward<U>(in)) {}

修复编译。

Demo.