C++ 为什么在“形成对引用类型的引用”映射中出现错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1155142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:03:49  来源:igfitidea点击:

Why do I get an error in "forming reference to reference type" map?

c++stl

提问by GManNickG

What is the alternative if I need to use a reference, and the data I am passing I cannot change the type of, hence I cannot really store a pointer to it?

如果我需要使用引用,并且我传递的数据无法更改类型,因此我无法真正存储指向它的指针,那么有什么替代方法?

Code:

代码:

    #include <map>     
    #include<iostream>
    #include<string>     

    using namespace std;

    int main()
    {
       string test;
       pair<string, string> p=pair<string, string>("Foo","Bar");
       map<pair<string, string>, string&> m;
       m[make_pair("aa","bb")]=test;

       return 0;
}

Error:

错误:

$ g++ MapPair.cpp /usr/include/c++/3.2.3/bits/stl_map.h: In instantiation of std::map<std::pair<std::string, std::string>, std::string&, std::less<std::pair<std::string, std::string> >, std::allocator<std::pair<const std::pair<std::string, std::string>, std::string&> > >': MapPair.cpp:15:
instantiated from here /usr/include/c++/3.2.3/bits/stl_map.h:221: forming reference to reference type
std::string&' MapPair.cpp: In function int main()': MapPair.cpp:16: no match for std::map, std::string&, std::less >,
std::allocator,
std::string&> > >& [std::pair]' operator /usr/include/c++/3.2.3/bits/stl_pair.h: At global scope: /usr/include/c++/3.2.3/bits/stl_pair.h: In instantiation of std::pair<const std::pair<std::string, std::string>, std::string&>': /usr/include/c++/3.2.3/bits/stl_tree.h:122: instantiated from std::_Rb_tree_node

$ g++ MapPair.cpp /usr/include/c++/3.2.3/bits/stl_map.h:在std::string&' MapPair.cpp 的实例化中 :在函数std::map、std::string&、std::less 中>, std::allocator, std::string&> > >& [std::pair]' 运算符 /usr/include/c++/3.2.3/bits/stl_pair.h: 在全局范围:/usr/include/c++ /3.2.3/bits/stl_pair.h:在std::_Rb_tree_node 的 实例化中std::map<std::pair<std::string, std::string>, std::string&, std::less<std::pair<std::string, std::string> >, std::allocator<std::pair<const std::pair<std::string, std::string>, std::string&> > >': MapPair.cpp:15:
instantiated from here /usr/include/c++/3.2.3/bits/stl_map.h:221: forming reference to reference type
int main()': MapPair.cpp:16: no match for

std::pair<const std::pair<std::string, std::string>, std::string&>': /usr/include/c++/3.2.3/bits/stl_tree.h:122: instantiated from

What am I doing wrong to cause this errror?

我做错了什么导致这个错误?

回答by GManNickG

You cannot store references. References are just aliases to another variable.

您不能存储引用。引用只是另一个变量的别名

The map needs a copy of the string to store:

地图需要一个字符串的副本来存储:

map<pair<string, string>, string> m;

The reason you are getting that particular error is because somewhere in map, it's going to do an operation on the mapped_typewhich in your case is string&. One of those operations (like in operator[], for example) will return a reference to the mapped_type:

您收到该特定错误的原因是因为在地图中的某个地方,它将对mapped_type您的情况进行操作string&。其中一个操作(例如 in operator[])将返回对 的引用mapped_type

mapped_type& operator[](const key_type&)

Which, with your mapped_type, would be:

其中,与您的mapped_type,将是:

string&& operator[](const key_type& _Keyval)

And you cannot have a reference to a reference:

并且您不能有对参考的参考:

Standard 8.3.4:

There shall be no references to references, no arrays of references, and no pointers to references.

标准 8.3.4:

不应有对引用的引用,没有引用数组,也没有指向引用的指针。



On a side note, I would recommend you use typedef's so your code is easier to read:

附带说明一下,我建议您使用typedef's 以便您的代码更易于阅读:

int main()
{
    typedef pair<string, string> StringPair;
    typedef map<StringPair, string> StringPairMap;

    string test;

    StringPair p("Foo","Bar");
    StringPairMap m;
    m[make_pair("aa","bb")] = test;

   return 0;

}

}

回答by voltrevo

The previous answers here are outdated. Today we have std::reference_wrapperas part of the C++11 standard:

这里以前的答案已经过时了。今天,std::reference_wrapper作为 C++11 标准的一部分,我们有:

#include <map>
#include <iostream>
#include <string>

using namespace std;

int main()
{
    string test;
    pair<string, string> p = pair<string, string>("Foo", "Bar");
    map<pair<string, string>, reference_wrapper<string>> m;
    m[make_pair("aa", "bb")] = test;

    return 0;
}

A std::reference_wrapper will convert implicitly to a reference to its internal type, but this doesn't work in some contexts, in which case you call .get()for access.

std::reference_wrapper 将隐式转换为其内部类型的引用,但这在某些上下文中不起作用,在这种情况下您需要.get()访问。

http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

回答by navigator

You can use boost::reference_wrapper to store references in STL containers. Here is your example modified (not tested, and definitely not very well written, just illustrates a point)

您可以使用 boost::reference_wrapper 在 STL 容器中存储引用。这是您修改的示例(未经测试,绝对不是写得很好,只是说明了一点)

#include <map>     
#include<iostream>
#include<string>   
#include <boost/ref.hpp>



int main()
{
   typedef std::pair< std::string, std::string> PairType;
   typedef std::map< PairType, boost::reference_wrapper<std::string> > MapType;
   std::string test = "Hello there!!";
   MapType m;
   PairType pp =  std::make_pair("aa","bb");
   m.insert(std::make_pair(pp , boost::ref(test) ) );

   MapType::iterator it (m.find( pp ) );
   if(it != m.end())
   {
       std::cout << it->second.get() << std::endl;
   }

   //change test
   test = "I am different now";
   std::cout << it->second.get() << std::endl;

   return 0;
}

回答by Junier

You cannot use references as the val, due to how the template is built. You could also use pointer instead.

由于模板的构建方式,您不能使用引用作为 val。您也可以改用指针。

回答by apostol

Essentially, the question is if you can use references in containers. Of course, you can, IFyou properly prepare your class ANDyour container. I demonstrate it below with two simple vector containers: vectorefwhich modifies std::vector<>and the other, vec, which is implemented from scratch.

本质上,问题是您是否可以在容器中使用引用。当然,你可以,如果你正确准备你的课程你的容器。我在下面用两个简单的向量容器来演示它:vectoref一个是修改std::vector<>,另一个vec是从头开始实现的。

#include <iostream>
#include <vector>

// requires compilation with --std=c++11 (at least)

using namespace std;

class A {
  int _a; // this is our true data
  A *_p; // this is to cheat the compiler

  public:
  A(int n = 0) : _a(n), _p(0)
  { cout << "A constructor (" << this << "," << _a << ")\n"; }
  // constructor used by the initializer_list (cheating the compiler)
  A(const A& r) : _p(const_cast<A *>(&r))
  { cout << "A copy constructor (" << this << "<-" << &r << ")\n"; }
  void print() const {cout << "A instance: " << this << "," << _a << "\n";}
  ~A() {cout << "A(" << this << "," << _a << ") destructor.\n";}
  // just to see what is copied implicitly
  A& operator=(const A& r) {
    cout << "A instance copied (" << this << "," << _a << ")\n";
    _a = r._a; _p = r._p;
    return *this;
  }
  // just in case you want to check if instance is pure or fake
  bool is_fake() const {return _p != 0;}
  A *ptr() const {return _p;}
};

template<typename T, int sz>
class vec { // vector class using initializer_list of A-references!!
  public:
  const T *a[sz]; // store as pointers, retrieve as references
  // because asignment to a reference causes copy operator to be invoked
  int cur;
  vec() : cur(0) {}
  vec(std::initializer_list<T> l) : cur(0) {
    cout << "construct using initializer list.\n";
    for (auto& t : l) // expecting fake elements
      a[cur++] = t.ptr();
  }
  const T& operator[](int i) {return *a[i];}
  // expecting pure elements
  vec& push_back(const T& r) {a[cur++] = &r; return *this;}
  void copy_from(vec&& r) {
    for (int i = 0; i < r.cur; ++i)
      push_back(r[i]);
  }
};

template<typename T>
class vectoref : public vector<T *> { // similar to vec but extending std::vector<>
  using size_type = typename vector<T*>::size_type;
  public:
  vectoref() {}
  vectoref(std::initializer_list<T> l) {
    cout << "construct using initializer list.\n";
    for (auto& t : l) // expecting fake elements
      vector<T*>::push_back(t.ptr());
  }
  const T& operator[](size_type i) {return *vector<T*>::at(i);}
  // expecting pure elements
  vectoref& push_back(const T& r)
  { vector<T*>::push_back(&r); return *this; }
  void copy_from(const vectoref&& r) {
    for (size_type i = 0; i < r.size(); ++i)
      vectoref<T>::push_back(r[i]);
  }
};

class X { // user of initializer_list of A
  public:
  X() {}
  void f(initializer_list<A> l) const {
    cout << "In f({...}):\n";
    for (auto& a : l)
      a.ptr()->print();
  }
};

int main()
{
  A a(7), b(24), c(80);
  cout << "----------------------------------\n";
  vectoref<A> w{a,a,b,c}; // alternatively, use next line
  // vec<A,5> w{a,a,b,c}; // 5-th element undefined
  w[0].print();
  w[3].print();
  cout << "----------------------------------\n";
  X x;
  x.f({a,b,c,a,b,c,b,a});
  cout << "==================================\n";
  return 0;
}