看得到想不到的坑:std::make_pair与std::pair<T1, T2>
今天捣鼓Rocstar,编译的时候碰上了一个C++11
的坑,属于那种不告诉你的话,给你代码你都看不出来异常的坑。出问题的那段代码长这样:
int node_id1 = fne[j],node_id2 = fne[(j+1)%nj]; if(node_id1>node_id2) std::swap(node_id1, node_id2); e2f_it = e2f.find(std::make_pair<int,int>(node_id1,node_id2)); if(e2f_it != e2f.end()){ afs.insert(std::make_pair<int,int>(e2f_it->second,i)); e2f.erase(e2f_it); } else{ e2f.insert(std::make_pair<std::pair<int,int>,int>( std::make_pair<int,int>(node_id1,node_id2) ,i)); }
上下文不怎么明确,但猜一猜也知道是怎么回事。看起来跟平时用的std::pair
没啥区别吧?然而它就是报错了:
Cannot convert parameter 1 from 'int' to 'int &&'
检查了半天,确定node_id1
和node_id2
兄弟俩确实是int
,这怎么可能错?实在受不了的我还去看了这一段的STL源码:
#if __cplusplus >= 201103L // NB: DR 706. template<typename _T1, typename _T2> constexpr pair<typename __decay_and_strip<_T1>::__type, typename __decay_and_strip<_T2>::__type> make_pair(_T1&& __x, _T2&& __y) { typedef typename __decay_and_strip<_T1>::__type __ds_type1; typedef typename __decay_and_strip<_T2>::__type __ds_type2; typedef pair<__ds_type1, __ds_type2> __pair_type; return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y)); } #else template<typename _T1, typename _T2> inline pair<_T1, _T2> make_pair(_T1 __x, _T2 __y) { return pair<_T1, _T2>(__x, __y); } #endif
显然,在201103L
之后,标准有过一次变更。Rocstar
估计就是那种万年gcc-4.8
的工程,所以估计用旧版本编译器就过去了。但新版究竟是怎么错的?看上面的新版代码也不知所以然。没办法,放下面子搜错误吧,还真在这里找到了,问题出在新版make_pair
的__decay_and_strip<_T1>
这部分。
具体来说,就是C++11
之后模板推导形式不一样了,合法的用法只有两种:
num_text.push_back(std::make_pair(num, text)); // deduced type num_text.push_back(std::pair<int, std::string>(num, text)); // specific type
作为一个从C++11
时代才开始深入学习的人来说,只有看到这里明明白说出来,才能想起来平时写std::make_pair
是不带尖括号的。
改起来就容易了,把原文中make_pair<int,int>
一类语句中的尖括号全删掉就好了。