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
Why do I get an error in "forming reference to reference type" map?
提问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:
std::string&' MapPair.cpp: In function
instantiated from here /usr/include/c++/3.2.3/bits/stl_map.h:221: forming reference to reference typeint 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 ofstd::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 typeint 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_type
which 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_wrapper
as 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: vectoref
which 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;
}