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

标签 c++ c++17 static-initialization noncopyable

我想初始化一个静态的std::map,其中的值是不可复制的。我将我的类(class)称为 ValueClassValueClass 有一个 std::unique_ptr 作为私有(private)成员,我什至通过扩展如下所示的 non_copyable 来确保 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() }
};

initializer_list 尝试复制此类时出现编译错误。

整个周末我都尝试编写自己的 make_map 函数,在很多小时内启用初始化而不复制,但我失败了。我试过了 this , thatother但它们都不能用 Visual Studio 15.9.4 编译。

如何使用 Visual Studio 编译器在不强制复制的情况下初始化静态 std::map,并且在一个函数中统一初始化?

编辑: 这是现实生活场景的简化版本,我正在努力使它正常工作(请原谅我缺乏命名约定和案例不一致):

#include <iostream>
#include <map>

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

class InnerValueClass : public non_copyable
{
public:
    InnerValueClass(const int inner_number) : inner_number_(inner_number) {  }
private:
    int inner_number_;
};

class ValueClass : public non_copyable
{
public:
    ValueClass(const int number1) : number1_(number1) {  }
    ValueClass(const bool condition) : condition_(condition), inner_value_(
        std::make_unique<InnerValueClass>(5)) {  }
private:
    int number1_{};
    bool condition_{};
    std::unique_ptr<InnerValueClass> inner_value_{};
};

/* Inline initialization of std::map copies, this is for initialization of non-copy types*/
template <typename TKey, typename TNonCopyableValue>
class make_map_by_moving
{
    typedef std::map<TKey, TNonCopyableValue> map_type;
    map_type map_;
public:
    make_map_by_moving(const TKey& key, TNonCopyableValue&& val)
    {
        map_.emplace(key, std::move(val));
    }
    make_map_by_moving<TKey, TNonCopyableValue>& operator()(const TKey& key, TNonCopyableValue&& val)
    {
        map_.emplace(key, std::move(val));
        return *this;
    }
    operator const map_type&()
    {
        return map_;
    }
};

static std::map<int, ValueClass> map =
        make_map_by_moving<int, ValueClass>
                (1, ValueClass(5))
                (2, ValueClass(true));
/* It goes on like this for hundreds of lines, so I really appreciate any
solution that leave me with a clean initialization rather than calling
functions on std::map */

int main() { }

重复编辑:该问题中提供的解决方案不适用于我拥有的类结构。我也在寻找修复 make_map_by_moving 函数的解决方案,换句话说就是内联初始化,答案是提供一个带有函数调用的命令式解决方案。

最佳答案

您不能直接执行此操作,因为 initializer_list 的所有元素都有 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();

此代码不对 non_copyable 执行任何复制。我们将构造放置在 map 内部,然后因为 get() 是纯右值,所以没有从 get() 复制/移动到值类get() 中的 m 对象value_classes

一个稍微偷偷摸摸的方法是为此滥用 try_emplace():

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

try_emplace()单独获取 key 类型(因此您可以只传递一个 int),然后单独获取用于放置的值的参数,这使得完成此操作的方式更加简洁。

关于c++ - 在统一的内联初始化中使用不可复制的值初始化静态 std::map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53806687/

相关文章:

c++ - 使用 libcurl 创建新目录

c++ - 如何从 PathCompactPath 的 Wnd 句柄获取 DC 句柄?

compiler-errors - 由于 c++17 无法编译 MK-Livestatus

c++ - 比较对象可作为 const 调用

c++ - 我可以在 C++ 中扩展变体吗?

java - 当嵌套枚举在其构造函数中引用父静态成员时,为什么会出现 NPE?

c++ - clang 和 gcc 在处理模板生成和静态 constexpr 成员时的不同行为?

C++ 多线程和 vector

c++ - 静态初始化顺序和字符串连接

c++ - 使用 Visual Studio 为 x64 编译?