问题 boost :: unordered_map.emplace(Args && ... args)如何工作?


根据 文件 它:

插入一个由对象构造的对象   参数args,在容器中   当且仅当没有元素时   具有等效键的容器。

但是可以插入到unordered_map中的唯一对象具有类型 std::pair<Key const, Mapped>(因为要插入的对象需要一个键和一个值),已知这个构造函数只有两个参数。那么为什么它使用可变函数形式呢?当然,我完全不了解这一点。


10549
2018-01-29 14:57


起源



答案:


看到 这个 有关emplace_back与push_back的文章。本质上,它允许从传递给它的参数构造一个对象,而不需要首先创建要传递的对象。它通过删除通常由于创建要插入的对象而发生的复制结构来节省开销。

所以你可以逃脱这个:

unordered_map<int,int> foo;
foo.emplace(4, 5);

代替

foo.insert(std::make_pair(4, 5));

更好的,(如果我没有记错的话),你可以通过这条路线:

struct Bar{
    int x,y;
    Bar(int _x, int _y) : x(_x), y(_y){}
};

unordered_map<int,Bar> baz;
baz.emplace(4, 5, 6);

并取自维基 的C ++ 0x

由于rvalue引用的措辞的性质,以及对左值引用(常规引用)的措辞的一些修改,rvalue引用允许开发人员提供完美的函数转发。当与可变参数模板结合使用时,此功能允许功能模板可以完美地将参数转发给另一个采用这些特定参数的函数。这对于转发构造函数参数,创建工厂函数非常有用,这些函数将自动为这些特定参数调用正确的构造函数。

其工作方式如下:

template<typename TypeToConstruct> struct SharedPtrAllocator {

    template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) {
        return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
    }
}

再次,从上面提到的Wiki文章中无耻地窃取。


8
2018-01-29 15:53



后一个例子对我来说很奇怪。假设我们有2个构造函数 Key: Key(int) 和 Key(int,int) 和2 Value: Value(int,int) 和 Value(int),编译器如何在构建a的情况下消除歧义 Key/Value 对? - Matthieu M.
先到先得,我服用?所以它创造了一个 X(int,int) 先是然后一个 X(int)。稍后会测试并发回。可能还没有编译并抛出“ambigious”编译时错误。 - Xeo
@Matthieu M.不知道,真的。问题是规范目前还没有完全正式化,所以我们无法确定这类问题应该如何回答,直到它为止。我们需要的是语言律师来解决我的答案所带来的任何含糊之处。我会在心跳中投票。 - wheaties


答案:


看到 这个 有关emplace_back与push_back的文章。本质上,它允许从传递给它的参数构造一个对象,而不需要首先创建要传递的对象。它通过删除通常由于创建要插入的对象而发生的复制结构来节省开销。

所以你可以逃脱这个:

unordered_map<int,int> foo;
foo.emplace(4, 5);

代替

foo.insert(std::make_pair(4, 5));

更好的,(如果我没有记错的话),你可以通过这条路线:

struct Bar{
    int x,y;
    Bar(int _x, int _y) : x(_x), y(_y){}
};

unordered_map<int,Bar> baz;
baz.emplace(4, 5, 6);

并取自维基 的C ++ 0x

由于rvalue引用的措辞的性质,以及对左值引用(常规引用)的措辞的一些修改,rvalue引用允许开发人员提供完美的函数转发。当与可变参数模板结合使用时,此功能允许功能模板可以完美地将参数转发给另一个采用这些特定参数的函数。这对于转发构造函数参数,创建工厂函数非常有用,这些函数将自动为这些特定参数调用正确的构造函数。

其工作方式如下:

template<typename TypeToConstruct> struct SharedPtrAllocator {

    template<typename ...Args> std::shared_ptr<TypeToConstruct> construct_with_shared_ptr(Args&&... params) {
        return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...));
    }
}

再次,从上面提到的Wiki文章中无耻地窃取。


8
2018-01-29 15:53



后一个例子对我来说很奇怪。假设我们有2个构造函数 Key: Key(int) 和 Key(int,int) 和2 Value: Value(int,int) 和 Value(int),编译器如何在构建a的情况下消除歧义 Key/Value 对? - Matthieu M.
先到先得,我服用?所以它创造了一个 X(int,int) 先是然后一个 X(int)。稍后会测试并发回。可能还没有编译并抛出“ambigious”编译时错误。 - Xeo
@Matthieu M.不知道,真的。问题是规范目前还没有完全正式化,所以我们无法确定这类问题应该如何回答,直到它为止。我们需要的是语言律师来解决我的答案所带来的任何含糊之处。我会在心跳中投票。 - wheaties


既然C ++标准库集成了Boost的那部分:

http://en.cppreference.com

#include <iostream>
#include <utility>
#include <tuple>

#include <unordered_map>

int main(){
    std::unordered_map<std::string, std::string> m;

    // uses pair's piecewise constructor
    m.emplace(std::piecewise_construct,
        std::forward_as_tuple("c"),
        std::forward_as_tuple(10, 'c'));

    for (const auto &p : m) {
        std::cout << p.first << " => " << p.second << '\n';
    }
}

std::piecewise_construct


5
2017-09-15 18:04