C++ 在统一的内联初始化中使用不可复制的值初始化静态std::map

C++ 在统一的内联初始化中使用不可复制的值初始化静态std::map,c++,c++17,static-initialization,noncopyable,C++,C++17,Static Initialization,Noncopyable,我想初始化一个静态的std::map,其中的值是不可复制的。我将给我的班级打电话ValueClassValueClass有一个std::unique\u ptr作为私有成员,我甚至通过扩展不可复制的来确保ValueClass不可复制,如下所示: class non_copyable { public: non_copyable() = default; protected: virtual ~non_copyable() = default; private: non_c

我想初始化一个静态的
std::map
,其中的值是不可复制的。我将给我的班级打电话ValueClassValueClass有一个
std::unique\u ptr
作为私有成员,我甚至通过扩展
不可复制的
来确保ValueClass不可复制,如下所示:

class non_copyable {
public:
    non_copyable() = default;
protected:
    virtual ~non_copyable() = default;
private:
    non_copyable(const non_copyable&) = delete;
    non_copyable& operator=(const non_copyable&) = delete;
};
现在,我尝试使用我的类作为值来定义std::map:

static std::map<int, ValueClass> value_classes = {
    {0, ValueClass()},
    {1, ValueClass() }
};

重复编辑:该问题中提供的解决方案不适用于我的类结构。我也在寻找一种解决方案,通过移动
函数来修复
生成我认为您需要在函数中使用
insert\u或\u assign
创建对象,然后返回它:

std::map<int, ValueClass> populate()
{
    std::map<int, ValueClass> value_classes;
    value_classes.insert_or_assign(std::make_pair(0, ValueClass());
    return value_classes;
}

还包括
functional

您不能直接执行此操作,因为
初始值设定项列表
对其所有元素都有
const
支持,并且必须将它们从初始值设定项列表复制到容器中。这显然需要复制。不幸的是,无法从初始值设定项列表中放置

在C++17中,由于保证了拷贝省略,您可以执行以下操作:

std::map<int, non_copyable> get() {
    std::map<int, non_copyable> m;
    m.emplace(std::piecewise_construct, std::tuple(0), std::tuple());
    m.emplace(std::piecewise_construct, std::tuple(1), std::tuple());
    return m;
}

std::map<int, non_copyable> value_classes = get();

单独获取键类型(因此您可以只传递一个
int
),然后分别传递用于放置的值的参数,这使得实现这一点的方法不那么繁琐。

您不能使用
初始值设定项\u list
将对象从
不可复制的
对象移动

您的类删除
复制构造函数
赋值运算符
。当您尝试使用
初始值设定项列表
初始化
映射
或任何其他
容器
时,
初始值设定项列表
严格强制您引用
左值
,并禁止
右值
移动或向前语义


这里有一篇非常好的博客文章,解释了所有的细节:以及一个类似的Q/a发现。

另一种方法是简单地调用
m[0];m[1]。它将放置默认构造的对象。请参阅。为什么
尝试使用_emplace
而不是简单的旧
emplace
?谢谢您的回答!我意识到我的问题不清楚,对此我很抱歉。我不想让这些值以后再定义,我也想定义这些值。我已经用代码更新了我的问题,代码显示了我正在经历的真实场景。@U.Bulle好吧,我不知道如果
InnerValueClass
不可复制,你希望你的
ValueClass(int,const InnerValueClass&)
构造函数如何工作,但除此之外,这个答案提供了一个提供任意构造函数参数的路径,非常好。感谢您提供了非常快速和信息丰富的答案。我已经用显示真实应用程序的代码更新了我的问题
insert_或_assign
也没有帮助它编译。我得到了
C2660'std::pair::pair':函数不接受两个参数,并且集成了Barry的建议:(我建议您更改您的特殊类以删除emplace的使用。Barry的代码或我的代码适用于您的案例,只需创建一个实际的函数。此外,您的代码中有一个很大的错误,因为引用包装指向一个已被破坏的临时类。您是对的。我编辑了问题和修复了引用包装,以避免分散其他读者的注意力。)(现在它是唯一的了。)你说我创建了一个实际的函数是什么意思?我尝试了这两种方法,但都没有编译成功。使用你的解决方案,我在“插入”或“分配”行上得到了5个不同的错误(不包括通过移动生成映射,我在单独的项目中进行了测试).我使用MSVC编译此映射是否意味着在第一次初始化后在运行时可编辑?我确实记得一个全局常量结构的建议(甚至实现),该结构提供自然初始化和类似映射的性能。我发现了以下链接:这可能会给你一些见解!
std::map<int, ValueClass> value_classes = populate();
std::map<int, ValueClass> populate()
{
    std::map<int, ValueClass> value_classes;
    value_classes.emplace(1, 5);
    return value_classes;
}
std::map<int, non_copyable> get() {
    std::map<int, non_copyable> m;
    m.emplace(std::piecewise_construct, std::tuple(0), std::tuple());
    m.emplace(std::piecewise_construct, std::tuple(1), std::tuple());
    return m;
}

std::map<int, non_copyable> value_classes = get();
std::map<int, non_copyable> get() {
    std::map<int, non_copyable> m;
    m.try_emplace(0);
    m.try_emplace(1);
    return m;
}