emplace_back不适用于 std::vector<std::map<int, int>>

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

本文关键字:std int gt lt map vector back 不适用 适用于 emplace      更新时间:2023-10-16

我正试图将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在这里起作用,但emplace_back不起作用。我怎样才能让emplace_back工作?

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

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

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

这是因为,虽然用大括号括起来的列表可能产生初始化器列表,但它不必这样做。它也可以是构造函数调用或类似的东西。写入

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

生成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)}

这整件事有点乱。

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

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

不起作用的原因是没有类型可以推导出来。例如,emplace_back试图推断输入类型的名称,但这是不可能的,因为大括号括起的列表有几种它可以描述的类型。因此没有匹配的函数调用

可以使用下面的辅助函数来实现:

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

问题是当我们写:

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

编译器不能推断实参的类型,也不能决定调用哪个构造函数。

基本思想是当你写一个像

这样的函数时
template<typename T>
void f(T) {}

,像

一样使用
f( {1,2,3,4} ); //error

你会得到编译错误,因为{1,2,3,4}没有类型。

但是如果你定义函数为

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

那么它可以完美地编译

如果我对这些问题报告理解正确的话,这似乎是目前不支持的:

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

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

相关文章: