创建移动构造对象的向量

时间:2018-09-19 23:40:43

标签: c++ move stdvector unique-ptr emplace

我有一个类,其中包含一个构造函数,该构造函数会在构造对象时移动它:

class SomeClass
{
private:
    const std::unique_ptr<Base> foo;

public:
    template <typename T>
    inline explicit SomeClass(T&& derived) noexcept
     : foo(std::make_unique<T>(derived))
    {
        static_assert(std::is_base_of<Base, T>::value);
    }
};

当我只需要一个实例时,可以毫无问题地构造该类的对象:

class Derived : public Base
{
    // ...
};

Derived bar(...);
SomeClass baz(std::move(bar));

// Or

SomeClass baz(Derived(...));

但是我无法将SomeClass类型的任何对象放置(或推入)到std::vector<SomeClass>

std::vector<SomeClass> vec;

Derived bar(...);
vec.emplace_back(std::move(bar)); // Does not work.

vec.emplace_back(Derived(...));   // Does not work.

请您解释一下为什么不能放置对象?我认为emplace_back使用的完美转发将允许就地构建SomeClass实例,就像可以构造单个实例一样。

请您还解释一下如何修改内容以构造std::vector<SomeClass>吗?

我的猜测是,由于构造函数参数是通过move传递的,因此它们不会在emplace_back方法中一直传递到构造函数。

1 个答案:

答案 0 :(得分:2)

std::vector::emplace_backvalue_type施加了以下要求:

  

类型要求

     

-T(容器的元素类型)必须满足MoveInsertableEmplaceConstructible的要求。

类的const成员隐式删除move构造函数,即由于SomeClassMoveInsertable不是const std::unique_ptr<Base> foo

解决方案:从const中删除foo

struct Base {};
struct Derived : public Base {};

class SomeClass
{
private:
    std::unique_ptr<Base> foo;

public:
    template <typename T>
    inline explicit SomeClass(T&& derived)
        noexcept(std::is_nothrow_constructible_v<decltype(foo), T&&>) // (1)
     : foo(std::make_unique<T>(std::forward<T>(derived))) // (2)
    {
        static_assert(std::is_base_of<Base, T>::value);
    }
};

int main()
{
    std::vector<SomeClass> vec;

    Derived bar{};
    vec.emplace_back(std::move(bar));

    vec.emplace_back(Derived{}); 
}

Live example

作为旁注,我建议根据noexcept(1)使std::is_nothrow_constructible为条件,并将std::forward<T>(derived)传递给std::make_unique以使用转发参考(2)。