创建移动构造对象的向量

Creating vector of move-constructed objects

我有一个 class,其中包含一个在构造过程中移动对象的构造函数:

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 的对象:

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 方法中的构造函数。

std::vector::emplace_backvalue_type 提出以下要求:

Type requirements

-T (the container's element type) must meet the requirements of MoveInsertable and EmplaceConstructible.

class 的 const 成员隐式删除移动构造函数,即 SomeClass 不是 MoveInsertable 因为 const std::unique_ptr<Base> foo.

解决方案:从 foo.

中删除 const
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.

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