简体   繁体   English

emplace_back不使用std :: vector <std::map<int, int> &gt;

[英]emplace_back not working with std::vector<std::map<int, int>>

I am trying to do emplace_back into a std::vector<std::map<int, int>> , but could not find the right syntax to do it. 我试图将emplace_back做成std::vector<std::map<int, int>> ,但找不到正确的语法来做到这一点。

#include<map>
#include<vector>

int main()
{
    std::vector<std::map<int, int>> v;
    std::map<int,int> a {{1,2}};

    v.push_back({{1,2}});

    v.emplace_back({1,2});    // error
    v.emplace_back({{1,2}});  // error
    v.emplace_back(({1,2}));  // error
}

push_back works here, but not emplace_back . push_back在这里工作,但不是emplace_back How can I get emplace_back working? 我怎样才能让emplace_back工作?

emplace_back does forward all arguments to a matching constructor of the member type. emplace_back确实将所有参数转发给成员类型的匹配构造函数。 Now, std::map has a initializer-list constructor, but it expects a list of std::pair<const Key, Value> , ie std::pair<const int, int> . 现在, std::map有一个初始化列表构造函数,但它需要一个std::pair<const Key, Value> ,即std::pair<const int, int> push_back is not a template, so it just expects one type and thus performs the conversion in place. push_back不是模板,因此它只需要一种类型,从而执行转换。 That is, no type-deduction occurs here. 也就是说,这里不会发生类型推断。

You would need to explicitly state that you want to have a std::pair ; 你需要明确声明你想拥有一个std::pair ; the following should work: 以下应该有效:

#include<map>
#include<vector>

int main()
{
    std::vector<std::map<int, int>> v;

    v.emplace_back(std::initializer_list<std::pair<const int, int>>{
            {1,2},{3,4},{5,6}});

    return 0;
}

For the same reason, this does not compile: 出于同样的原因,这不编译:

    v.emplace_back({std::pair<const int,int>(1,2),
                    std::pair<const int,int>(3,4)});

This is because, though a brace-enclosed list may yield an initializer-list, it doesn't have to. 这是因为,虽然括号括起的列表可能会产生初始化列表,但它不必。 It can also be a constructor call or something like that. 它也可以是构造函数调用或类似的东西。 So, writing 所以,写作

auto l = {std::pair<const int,int>(1,2),
          std::pair<const int,int>(3,4)};

yields an initializer list for l , but the expression itself might be used in another way: 产生l的初始化列表,但表达式本身可能以另一种方式使用:

std::pair<std::pair<const int, int>, std::pair<const int, int>> p =
          {std::pair<const int,int>(1,2),
          std::pair<const int,int>(3,4)}

This whole stuff gets a bit messy. 整个东西有点乱。

Basically, if you have an brace-enclosed-list, it may yield an initializer list or call a matching constructor. 基本上,如果你有一个大括号括号列表,它可能会产生一个初始化列表或调用匹配的构造函数。 There are cases where the compiler is not able to determine which types are needed; 在某些情况下,编译器无法确定需要哪些类型; emplace_back is one of them (because of forwarding). emplace_back就是其中之一(因为转发)。 In other cases it does work, because all types are defined in the expression. 在其他情况下,它确实有效,因为所有类型都在表达式中定义。 Eg: 例如:

#include <vector>
#include <utility>

int main() 
{
    std::vector<std::pair<const int, int>> v = 
         {{1,2},{3,4},{5,6}};
    return 0;
}

Now the reason it doesn't work is that no type can be deduced. 现在它不起作用的原因是不能推断出任何类型。 Ie emplace_back tries to deduce the name of the input types, but this is not possible, since a brace-enclosed-list has several types it can describe. emplace_back尝试推断输入类型的名称,但这是不可能的,因为大括号括号列表有几种类型可以描述。 Hence there is not a matching function call. 因此,没有匹配的函数调用。

One can achieve that using a helper function as follows: 可以使用辅助函数实现如下:

 #include <map>
 #include <vector>

 void emplace_work_around(
    std::vector<std::map<int, int>>& v,
    std::initializer_list<std::pair<const int,int>> && item
 )
 {
    v.emplace_back(std::forward<std::initializer_list<std::pair<const int,int>>>(item));
 }

int main()
{
    std::vector<std::map<int, int>> v;

    emplace_work_around(v,{{1,2}});
}

The problem was when we write: 问题出在我们写的时候:

v.emplace_back({{1,2}});  // here {{1,2}} does not have a type.

the compiler is not able to deduce the type of the argument, and it can't decide which constructor to call. 编译器无法推断出参数的类型,也无法决定调用哪个构造函数。

The underlying idea is that when you write a function like 根本的想法是,当你写一个像这样的函数

template<typename T>
void f(T) {}

and use it like 并使用它

f( {1,2,3,4} ); //error

you will get compiler error, as {1,2,3,4} does have a type. 你会得到编译器错误,因为{1,2,3,4}确实有类型。

But if you define your function as 但是如果你将你的功能定义为

template<typename T>
void f(std::initializer_list<T>) {}
 f( {1,2,3,4} );

then it compiles perfectly. 然后它完美地编译。

This seems to be currently unsupported, if I understand these issue reports right: 如果我理解这些问题报告的话,这似乎目前不受支持:

http://cplusplus.github.io/LWG/lwg-active.html#2089 http://cplusplus.github.io/LWG/lwg-active.html#2089

http://cplusplus.github.io/LWG/lwg-active.html#2070 http://cplusplus.github.io/LWG/lwg-active.html#2070

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM