如果 T 具有显式构造函数,则无法使用 emplace new 将元素添加到 container<T>

Posted

技术标签:

【中文标题】如果 T 具有显式构造函数,则无法使用 emplace new 将元素添加到 container<T>【英文标题】:Can't add element into container<T> with emplace new if T has explicit constructor 【发布时间】:2021-04-30 02:53:25 【问题描述】:

我正在编写一个固定大小的容器类型,放置新。 当我测试它时,我发现如果类型 T 有明确的 ctor,我的“emplace_back()”之类的函数就不会编译。

这是一个代码示例(缺少删除调用等):

#include <iostream>

template <typename T>
struct TestType

   explicit TestType(T value) // removing explicit makes it a compileable code
   
      std::cout << value << std::endl;
   
;

template <typename... Args>
void emplace(TestType<int>* buffer, Args&&... args)

     // placement new // compile time error in this line
    new (buffer) TestType<int>(std::forward<TestType<int>>(args)...);


int main()

    TestType<int>* buffer;
    buffer = (static_cast<TestType<int>*>(::operator new(sizeof(TestType<int>) * 10)));
   
    emplace(buffer, 5);
   
    return 0;

错误是: " 在 'void emplace(TestType*, Args&& ...) [with Args = int]' 的实例化中: 24:22:从这里需要 16:64:错误:没有匹配的函数调用'forward(int&)'"

*** 上有一些类似的问题,但是这些主要是关于 std::map 的,可能我的问题不同。 (如果没有,我仍然不明白发生了什么。)

如果(例如)std::vector emplace_back() 适用于任何具有显式 ctor 的 T 类型,为什么它不适用于我的容器类型? 这编译得很好:

#include <iostream>
#include <vector>

template <typename T>
struct TestType

   explicit TestType(T value)
   
;

int main()

    std::vector<TestType<int>> vector;
    vector.emplace_back(5);
     
    return 0;

感谢您的帮助!

【问题讨论】:

【参考方案1】:

您将TestType&lt;int&gt; 指定为std::forward 的模板参数为std::forward&lt;TestType&lt;int&gt;&gt;(args)...,这意味着您将参数转发为TestType&lt;int&gt;。尝试将传递的参数隐式转换为TestType&lt;int&gt;,这不起作用,因为转换构造函数被标记为explicit

您应该将Args 指定为std::forward 的模板参数,即将参数转发为:

template <typename... Args>
void emplace(TestType<int>* buffer, Args&&... args)

    // placement new
    new (buffer) TestType<int>(std::forward<Args>(args)...);
    //                                      ^^^^

【讨论】:

非常感谢!在我的原始示例中(使用 std::forward>(args)...),如果我删除了显式关键字,在这种情况下,由于隐式转换,将调用默认 ctor,然后调用 TestType 的移动 ctor 也被调用。所以这是应该使用 std::forward 的另一个原因。这是真的吗? @thamas 是的,对于这种情况,首先通过转换构造函数构造一个临时的TestType&lt;int&gt;,然后移动临时的。甚至copy elision 可能会被应用临时构建是多余的。 谢谢@songyuanyao!

以上是关于如果 T 具有显式构造函数,则无法使用 emplace new 将元素添加到 container<T>的主要内容,如果未能解决你的问题,请参考以下文章

构造函数和析构函数

如果复制列表初始化允许显式构造函数会出现啥问题?

为啥显式允许默认构造函数和具有 2 个或更多(非默认)参数的构造函数?

显式构造函数和重载

C++——构造函数和析构函数

来自 T* 的 std::unique_ptr<T> 的构造函数显式背后的原因是啥?