在使用聚合初始化时是否可以在 map 中执行 no-copy emplace?

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

查看此答案,了解如何在不复制映射值的情况下插入

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

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

然后像这样使用聚合初始化进行初始化

Foo{7}

Foo{7, std::mutex()}

是否有可能以某种方式放置到类型为地图中?:

std::map<size_t, Foo> mymap;

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

Link 到编译器资源管理器:

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::pair 一样,std::map::try_emplace 也不是什么大问题。因为这个简单的声明将重现一个根源于同一问题的错误:

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'tor,或者使用像Passer By.[=18这样的东西=]

有一篇正在撰写中的论文 (p0960) 旨在在未来的标准修订中解决它,但只有时间才能证明它将如何演变。