将取自std :: map的std :: pair引用传递给接受std :: pair引用的函数

时间:2018-07-11 12:35:32

标签: c++ c++11 stdmap

编辑:第一个问题的答案是使用std :: pair。对第二个问题有什么想法(标记为“奖励问题”)?

使用以下代码:

#include <map>
#include <vector>

void foo(std::pair<int, int>& p)  // EDIT: it needs to be non-const
{}

int main()
{
    std::pair<int, int> p{1,2};
    foo(p);
    std::vector<std::pair<int, int>> v{{1,2}};
    for (auto& element : v)
    {
        foo(element);  // works fine
    }

    std::map<int, int> m{std::make_pair(1,2)};
    //std::map<int, int> m2{{1,2}};
    for (auto& element : m)  // the problematic loop
    {
        foo(element);
    }

    return 0;
}

我在后面的for循环中收到带有m的以下消息:

  

错误:来自“ std :: pair&”类型的引用的无效初始化   'std :: pair'类型的表达式

,然后在该位置加上m2:

  

错误:类型的非常量引用无效的初始化   类型为“ std :: pair”的右值中的“ std :: pair&”

那是为什么?

奖励问题: 我发现非常奇怪的是,当未注释掉m2的初始化并且for循环保持不变(仍然有m且从未使用过m2)时,错误消息将从

更改
  

错误:来自“ std :: pair&”类型的引用的无效初始化   'std :: pair'类型的表达式

  

错误:类型的非常量引用无效的初始化   类型为“ std :: pair”的右值中的“ std :: pair&”

我很想知道你对此的想法。我用onlinegdb.com测试了这段代码

3 个答案:

答案 0 :(得分:6)

The container makes the key const(这适用于所有关联容器):

value_type    std::pair<const Key, T>

因此它应该是void foo(std::pair<int const, int>& p)

答案 1 :(得分:4)

the documentation

map::value_type = std::pair<const Key, T>

含义

map<int,int>::value_type = pair<const int, int>

因此,编译器可以将pair<const int,int>&类型的元素隐式转换为pair<int,int>类型的临时(右值),但这不能由非const ref传递给该函数。

将参数类型更改为pair<const int,int>,或按值将其接受。


作为参考,gcc 6.3提供了这个非常有用的错误:

prog.cpp: In function ‘int main()’:
prog.cpp:21:13: error: invalid initialization of non-const reference of type ‘std::pair<int, int>&’ from an rvalue of type ‘std::pair<int, int>’
         foo(element);
             ^~~~~~~
In file included from /usr/include/c++/6/bits/stl_algobase.h:64:0,
                 from /usr/include/c++/6/bits/stl_tree.h:63,
                 from /usr/include/c++/6/map:60,
                 from prog.cpp:1:
/usr/include/c++/6/bits/stl_pair.h:272:19: note:   after user-defined conversion: constexpr std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = const int; _U2 = int; typename std::enable_if<(std::_PCC<((! std::is_same<_T1, _U1>::value) || (! std::is_same<_T2, _U2>::value)), _T1, _T2>::_ConstructiblePair<_U1, _U2>() && std::_PCC<((! std::is_same<_T1, _U1>::value) || (! std::is_same<_T2, _U2>::value)), _T1, _T2>::_ImplicitlyConvertiblePair<_U1, _U2>()), bool>::type <anonymous> = 1u; _T1 = int; _T2 = int]
         constexpr pair(const pair<_U1, _U2>& __p)
                   ^~~~
prog.cpp:4:6: note:   initializing argument 1 of ‘void foo(std::pair<int, int>&)’
 void foo(std::pair<int, int>& p)

请特别注意有关用户定义转换后的强大线索 ...

答案 2 :(得分:3)

您不允许修改地图的键,因此可以:

#include <map>
#include <vector>

// foo can modify the first value of the pair
void foo(std::pair<int, int>& p)
{}
// fooConstFirst cannot modify the first value of the pair
void fooConstFirst(std::pair<const int, int>& p)
{}

int main()
{
  std::pair<int, int> p{1,2};
  foo(p);
  std::vector<std::pair<int, int>> v{{1,2}};
  for (auto& element : v)
  {
    foo(element);
  }

  std::map<int, int> m{std::make_pair(1,2)};
  for (auto& element : m)
  {
    fooConstFirst(element);
  }

  return 0;
}