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

jha*_*a-G 25 c++ c++11

我试图做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
}
Run Code Online (Sandbox Code Playgroud)

push_back在这里工作,但不是emplace_back.我怎样才能emplace_back工作?

Kle*_*ern 13

emplace_back将所有参数转发给成员类型的匹配构造函数.现在,std::map有一个初始化列表构造函数,但它需要一个列表std::pair<const Key, Value>,即std::pair<const int, int>.push_back不是模板,所以它只需要一种类型,从而执行转换.也就是说,这里不会发生类型推断.

你需要明确说明你想要一个std::pair; 以下应该有效:

#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;
}
Run Code Online (Sandbox Code Playgroud)

出于同样的原因,这不编译:

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

这是因为,虽然括号括起的列表可能会产生初始化列表,但它不必.它也可以是构造函数调用或类似的东西.所以,写作

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

产生初始化列表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)}
Run Code Online (Sandbox Code Playgroud)

这整件事情有点乱.

基本上,如果你有一个大括号括号列表,它可能会产生一个初始化列表或调用匹配的构造函数.在某些情况下,编译器无法确定需要哪些类型; emplace_back是其中之一(因为转发).在其他情况下,它确实有效,因为所有类型都在表达式中定义.例如:

#include <vector>
#include <utility>

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

现在它不起作用的原因是不能推断出任何类型.即emplace_back尝试推断输入类型的名称,但这是不可能的,因为大括号括号列表有几种类型可以描述.因此,没有匹配的函数调用.


jha*_*a-G 7

可以使用辅助函数实现如下:

 #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}});
}
Run Code Online (Sandbox Code Playgroud)

问题出在我们写的时候:

v.emplace_back({{1,2}});  // here {{1,2}} does not have a type.
Run Code Online (Sandbox Code Playgroud)

编译器无法推断出参数的类型,也无法决定调用哪个构造函数.

根本的想法是,当你写一个像这样的函数

template<typename T>
void f(T) {}
Run Code Online (Sandbox Code Playgroud)

并使用它

f( {1,2,3,4} ); //error
Run Code Online (Sandbox Code Playgroud)

你会得到编译器错误,因为{1,2,3,4}确实有一个类型.

但是如果你将你的功能定义为

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

然后它完美地编译.