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

时间:2009-07-20 18:32:19

标签: c++ stl

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

代码:

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

错误:

  

$ g ++ MapPair.cpp   /usr/include/c++/3.2.3/bits/stl_map.h:   在实例化   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&amp ;,   std :: less&gt;,
  的std ::分配器,
  的std :: string&安培;&GT; &GT; &GT;&安培; [std :: pair]'运算符   /usr/include/c++/3.2.3/bits/stl_pair.h:   在全球范围内:   /usr/include/c++/3.2.3/bits/stl_pair.h:   在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的实例化中

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

5 个答案:

答案 0 :(得分:33)

您无法存储参考文献。引用只是aliases to another variable

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

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

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

mapped_type& operator[](const key_type&)

与您的mapped_type一起,将是:

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

你不能引用参考文献:

  

标准8.3.4:

     

不应引用引用,不引用引用数组,也不引用引用指针。


在旁注中,我建议您使用typedef,以便您的代码更易于阅读:

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;

}

答案 1 :(得分:20)

此前的答案已过时。今天我们将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;
}

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

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

答案 2 :(得分:9)

您可以使用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;
}

答案 3 :(得分:2)

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

答案 4 :(得分:1)

基本上,问题是,如果你可以在容器中使用引用。当然,你可以 IF 为你的容器准备好你的课程。我在下面用两个简单的向量容器演示它: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; } 从头开始实现。

{{1}}