代码之家  ›  专栏  ›  技术社区  ›  Sasha

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

  •  20
  • Sasha  · 技术社区  · 15 年前

    如果我需要使用引用,并且我传递的数据不能更改的类型,因此我不能真正存储指向它的指针,那么还有什么选择呢?

    代码:

        #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++映射空气.cpp /UR/COMPI/C++/3.2.3/BIT/STLYMAP.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 功能 int main()': MapPair.cpp:16: no match for 标准::映射,标准::字符串&, STD::
    STD::分配器,
    std::string&>>>&[std::pair]运算符 /UR/COMPI/C++/3.2.3/BIT/STLLIONGON: H: 在全球范围内: /UR/COMPI/C++/3.2.3/BIT/STLLIONGON: 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 标准:树节点

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

    5 回复  |  直到 7 年前
        1
  •  32
  •   Frxstrem    9 年前

    不能存储引用。参考文献只是 aliases to another variable .

    映射需要字符串的副本来存储:

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

    您得到这个特定错误的原因是因为在地图的某个地方,它将在 mapped_type 你的情况是 string& . 其中一个操作(比如 operator[] 例如)将返回对 马氏型 :

    mapped_type& operator[](const key_type&)
    

    它,和你的 马氏型 ,将是:

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

    并且不能引用引用:

    标准83.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;
    

    }

        2
  •  19
  •   voltrevo    11 年前

    这里以前的答案已经过时了。今天我们有 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_包装器将隐式转换为对其内部类型的引用,但在某些上下文中不起作用,在这种情况下,您可以调用 .get() 用于访问。

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

        3
  •  8
  •   navigator    15 年前

    可以使用boost::reference_包装器将引用存储在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;
    }
    
        4
  •  2
  •   Junier    15 年前

    由于模板是如何构建的,因此不能将引用用作VAL。您也可以使用指针。

        5
  •  1
  •   apostol    7 年前

    本质上,问题是 如果可以在容器中使用引用 . 当然,你可以, 如果 你要好好准备你的课 你的容器。我在下面用两个简单的向量容器演示它: 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;
    }