1

有关如何在不复制地图值的情况下插入

std::map 没有复制值

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

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

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

Foo{7}

或者

Foo{7, std::mutex()}

是否有可能以某种方式放置到带有 type 的地图中?:

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

4

2 回答 2

5

你可以利用强制转换来间接你的构造

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

请注意,您不能通过将临时对象绑定到非堆栈引用来延长临时对象的生命周期。

于 2019-03-04T11:24:12.027 回答
4

这不是问题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'tor,或者使用类似Passer By聪明解决方案

有一篇正在进行中的论文 ( p0960 ) 旨在在未来的标准修订中解决这个问题,但只有时间会告诉我们它将如何发展。

于 2019-03-04T12:10:55.350 回答