STL中map容器使用自定义key类型报错详解

来源:转载     2016-06-30 10:07:44    人气:     我有话说( 0 人参与)

引言STL的map容器中,key的类型是不是随意的呢?实践编写测试代码定义一个结构体来试试:[cpp]view plaincopystructa{char*pName;intm_a;}

引言

STL的map容器中,key的类型是不是随意的呢?
 

实践

编写测试代码

定义一个结构体来试试:

struct a
{  
    char* pName;
    int m_a;
};

...

map<a, int> mp;
    a a1;  
    a1.m_a      = 100;
    a1.pName    = "a1";
    a a2;
    a2.m_a      = 200;
    a2.pName    = "a2";
    mp.insert(std::make_pair(a1, 1));
    mp.insert(std::make_pair(a2, 1));

编译出错

初始化结构体对象,添加到容器中,编译程序:
f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)”: 无法从“const a”为“const std::_Tree<_Traits> &”推导 模板 参数  
1>        f:\vs2008\vc\include\xtree(1466) : 参见“std::operator <”的声明  
1>        f:\vs2008\vc\include\functional(142): 编译类 模板 成员函数“bool std::less<_Ty>::operator ()(const _Ty &,const _Ty &) const”时  
1>        with  
1>        [  
1>            _Ty=a  
1>        ]  
1>        f:\vs2008\vc\include\map(68): 参见对正在编译的类 模板 实例化“std::less<_Ty>”的引用  
1>        with  
1>        [  
1>            _Ty=a  
1>        ]  
1>        f:\vs2008\vc\include\xtree(22): 参见对正在编译的类 模板 实例化“std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,_Mfl>”的引用  
1>        with  
1>        [  
1>            _Kty=a,  
1>            _Ty=int,  
1>            _Pr=std::less<a>,  
1>            _Alloc=std::allocator<std::pair<const a,int>>,  
1>            _Mfl=false  
1>        ]  
1>        f:\vs2008\vc\include\xtree(63): 参见对正在编译的类 模板 实例化“std::_Tree_nod<_Traits>”的引用  
1>        with  
1>        [  
1>            _Traits=std::_Tmap_traits<a,int,std::less<a>,std::allocator<std::pair<const a,int>>,false>  
1>        ]  
1>        f:\vs2008\vc\include\xtree(89): 参见对正在编译的类 模板 实例化“std::_Tree_ptr<_Traits>”的引用  
1>        with  
1>        [  
1>            _Traits=std::_Tmap_traits<a,int,std::less<a>,std::allocator<std::pair<const a,int>>,false>  
1>        ]  
1>        f:\vs2008\vc\include\xtree(107): 参见对正在编译的类 模板 实例化“std::_Tree_val<_Traits>”的引用  
1>        with  
1>        [  
1>            _Traits=std::_Tmap_traits<a,int,std::less<a>,std::allocator<std::pair<const a,int>>,false>  
1>        ]  
1>        f:\vs2008\vc\include\map(78): 参见对正在编译的类 模板 实例化“std::_Tree<_Traits>”的引用  
1>        with  
1>        [  
1>            _Traits=std::_Tmap_traits<a,int,std::less<a>,std::allocator<std::pair<const a,int>>,false>  
1>        ]  
1>        f:\fileoprate\fileoprate\fileoprate.cpp(49): 参见对正在编译的类 模板 实例化“std::map<_Kty,_Ty>”的引用  
1>        with  
1>        [  
1>            _Kty=a,  
1>            _Ty=int  
1>        ]  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)”: 无法从“const a”为“const std::vector<_Ty,_Alloc> &”推导 模板 参数  
1>        f:\vs2008\vc\include\vector(1320) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)”: 无法从“const a”为“const std::basic_string<_Elem,_Traits,_Alloc> &”推导 模板 参数  
1>        f:\vs2008\vc\include\string(150) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)”: 无法从“const a”为“const _Elem *”推导 模板 参数  
1>        f:\vs2008\vc\include\string(140) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &)”: 无法从“const a”为“const std::basic_string<_Elem,_Traits,_Alloc> &”推导 模板 参数  
1>        f:\vs2008\vc\include\string(130) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)”: 无法从“const a”为“const std::reverse_iterator<_RanIt> &”推导 模板 参数  
1>        f:\vs2008\vc\include\xutility(2236) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::_Revranit<_RanIt,_Base> &,const std::_Revranit<_RanIt2,_Base2> &)”: 无法从“const a”为“const std::_Revranit<_RanIt,_Base> &”推导 模板 参数  
1>        f:\vs2008\vc\include\xutility(2046) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2784: “bool std::operator <(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)”: 无法从“const a”为“const std::pair<_Ty1,_Ty2> &”推导 模板 参数  
1>        f:\vs2008\vc\include\utility(84) : 参见“std::operator <”的声明  
1>f:\vs2008\vc\include\functional(143) : error C2676: 二进制“<”: “const a”不定义该运算符或到预定义运算符可接收的类型的转换

定位错误

定位到第一个错误行的代码位置:f:\vs2008\vc\include\functional(143) :143行代码:
// TEMPLATE STRUCT less
emplate<class _Ty>
struct less
    : public binary_function<_Ty, _Ty, bool>
{   // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
    {   // apply operator< to operands
    return (_Left < _Right);
    }
};

 

原因是less结构中对key对象进行了大小比较,但是我们自定义的key类型a并没有对<操作符进行重载,于是报错。

 

那么map容器和less有什么关系呢,我们的代码怎么回链接到这里了?

看看map的模板定义就知道了:

template<class _Kty,
    class _Ty,
    class _Pr = less<_Kty>,
    class _Alloc = allocator<pair<const _Kty, _Ty> > >
    class map
没错,申明map容器时,我们忽略了后面两个模板类,于是默认的使用了less进行比较。

 

关于这个_Pr详解可见:http://www.cnblogs.com/zjfdlut/archive/2011/08/12/2135698.html


解决方法

好了,知道了出错原因,我们就自己重载<操作符了:

bool operator<(const a& a1, const a& a2)
{
    if ( a1.m_a>=a2.m_a )
        return false;
    return true;
}

 

编译OK,可以使用了。

 

结论

因此,通过重载<操作符可以使自定义结构支持map容器。

 

另外的一种方法


下面介绍另一种方法,通过重写比较类函数来:
template<class T>
class Compare
{  
public:
    int operator()(const T& x, const T& y)const
    {
        if ( x.m_a>=y.m_a )
            return 0;
        return 1;
    }
};
在定义map容器时,第三个模板类传入我们自己定义的类而不是用默认的:
map<a, int, Compare<a>> mp;
    a a1;
    a1.m_a      = 100;
    a1.pName    = "a1";
    a a2;
    a2.m_a      = 200;
    a2.pName    = "a2";
    mp.insert(std::make_pair(a1, 1));
    mp.insert(std::make_pair(a2, 1));

编译也OK了。至于为什么要这么做,这篇博文讲的很详细到位:http://www.cnblogs.com/zjfdlut/archive/2011/08/12/2135698.html,我就不赘余了。

STL map 自定义key 报错

本文源自互联网,采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可,
版权归原作者,如有问题请联系service@tsingfun.com (编辑:admin)
分享到: