使用聚合初始化时,是否可以将无拷贝置换到地图中

Is it possible to do a no-copy emplace into map while using aggregate initialization?

本文关键字:拷贝 地图 初始化 是否      更新时间:2023-10-16

请参阅此答案,以了解如何插入stdmap而不制作地图值的副本。

std :: map emplace而不复制值

继续从该答案继续 - 假设我的Foo类型看起来像这样:

struct Foo {
  const int& intref_; 
  std::mutex mutex_;
}

然后使用像这样的骨料发作初始化

Foo{7}

Foo{7, std::mutex()}

是否有可能用类型将其放入地图上?:

std::map<size_t, Foo> mymap;

我知道我可以为Foo编写一个构造函数 - 但是可以用汇总初始化来完成吗?

链接到编译器资源管理器:

https://godbolt.org/z/_fm4k1

相关的C 参考:

https://en.cppreference.com/w/cpp/container/map/try_emplace

https://en.cppreference.com/w/cpp/language/aggregate_initialization

您可以利用铸件来间接构造

template<typename T>
struct tag { using type = T; };
template<typename F>
struct initializer
{
    F f;
    template<typename T>
    operator T() &&
    {
        return std::forward<F>(f)(tag<T>{});
    }
};
template<typename F>
initializer(F&&) -> initializer<F>;
template<typename... Args>
auto initpack(Args&&... args)
{
    return initializer{[&](auto t) {
        using Ret = typename decltype(t)::type;
        return Ret{std::forward<Args>(args)...};
    }};
}

并将其用作

struct Foo
{
  const int& intref_; 
  std::mutex mutex_;
};
void foo()
{
    int i = 42;
    std::map<int, Foo> m;
    m.emplace(std::piecewise_construct,
              std::forward_as_tuple(0),
              std::forward_as_tuple(initpack(i)));
}

请注意,您不能通过将其绑定到非堆栈参考来延长临时的寿命。

这不是std::map::try_emplace的问题,而是std::pair。由于此简单的声明将重现植根于同一问题的错误:

std::pair<const int, Foo> p(
    std::piecewise_construct,
    std::forward_as_tuple(0),
    std::forward_as_tuple(i)
);

,仅std::pair并不是真正的问题。作为N4462详细信息的摘要,这很普遍。简而言之,那对c'tor(许多库函数也是如此)这样的转发:

second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)

因此没有卷曲牙套,因此在C 17中没有汇总初始化,仅值初始化。您唯一的选择是定义实际的c'tor,或使用的聪明解决方案之类的东西。

如果您可以使用C 20,则接受(P0960),这允许从括号的值列表中初始化聚合。这是一个地址N4462,允许用户代码也可以完善汇总的转发初始化器。