zoukankan      html  css  js  c++  java
  • VC6.0 list sort出错

    在STL中,排序是个很重要的话题。

    1.algorithm 里的sort()只接收RandomAccessIterator
    用于像vector,dequeue的排序

    2.像set,map,这种关联式容器,本身就由RBTree维护了有序,只要遍历一遍就行了。

    3.而list比较特殊一点,由于只有BidirectionalIterator。而又不本身有序。
    所以该容器自带了一个用来排序的函数。

    现在有个问题,如果在list里面存的是char*的元素。
    那么排序的时候,就会按照指针的大小来排。
    而如果我们本来用char*来表达一个字符串的话,这样就不符合要求了。(见下例输出1)

    而list.sort有一个带参数的用法。
    可以设计一个函数(如下的mycmp),传给list.sort。

    这种用法我一直感觉很纠结,因为list.sort的参数是
    greater<T>
    也就是一个functor(函数对象,函子,仿函数),本质上是一个类。
    而把函数名(本质上是个指针)传进去做参数。。。居然也可以。。

    从我们使用的语义上来说,似乎是可以的,因为functor传进去了之后,
    会调用该类的“()”操作符,也就是我们会把他视作一个函数来使用。
    可是明明他们就是不同的东西。。。

    这种用法在DEV-C下可以通过。(貌似VS也可以)

    在DEV-C下的例子

    #include <iostream>
    #include <list>
    #include <string.h>
    #include <iterator>

    using namespace std;

    char *ss[] = { "bb" , "aa" , "cc" , "ee" , "dd" } ;

    bool mycmp( char *&s1 , char *&s2){
        return strcmp(s1 , s2) == -1 ;
    }

    int main(){
        list<char*> l(ss , ss + sizeof(ss) / sizeof(char*)) ;
        ostream_iterator<char*> oit(cout , " ") ;//构造输出迭代器 
        copy( l.begin() , l.end() , oit) ;cout<<endl;//输出原序列 
        l.sort() ;//默认的排序,其实是按指针大小排序 
        copy( l.begin() , l.end() , oit) ;cout<<endl;//输出1 
        l.sort(mycmp);//传入函数指针的排序 
        copy( l.begin() , l.end() , oit) ;cout<<endl;//输出2 
        system("pause");
        return 0 ;
    }

    输出:

    bb aa cc ee dd
    bb aa cc ee dd
    aa bb cc dd ee

    可见不带参数的是按指针从小到大排序的。

    而这段在VC6里就会报错,即使把mycmp加上ptr_fun的修饰也不行。

    主要是list的sort参数实在太奇怪了。
    STL里面有很多函数提供两个版本,其中一个以默认方式进行比较,
    另一个版本可以允许传入一个functor,以该functor进行比较。

    而这个list.sort直接限定死了传进去的是greater<T>

    比如,我们直接设计一个functor

    struct c{
        operator()(char *&s1 , char *&s2){
            return strcmp(s1,s2) == -1 ;
        }
    };

    后面调用:l.sort(c());

    编译器会给出下面的信息:

    cannot convert parameter 1 from 'struct c' to 'struct std::greater<char *>'
            No constructor could take the source type, or constructor overload resolution was ambiguous

    其实就是类型不匹配。。。-_-编译器只认greater这个functor。

    虽然我们可以改变greater的实现,但是那样,把代码复制到其他地方,
    执行的结果肯定就不一样了。。。

    就是这里纠结了很久。。后来终于不小心搞定了,用特化!!

    像下面这样:(代码直接从泛化的greater复制过来,做相应修改就可以了)

        struct greater<char*> : binary_function<char*, char*, bool> {
        bool operator()(const char*& _X, const char*& _Y) const
            {return (strcmp(_X,_Y) == -1); }
        };


    在DEV里面,全特化要求加入 template<>开头,VC里面可以不加。

    那么后面直接这样调用就可以了:l.sort(greater<char*>()) ;

    这时编译器选择的就不是前面泛化的greater了,就是我们量身定做的char* 的greater。

    且慢,在VC6里面还要报错。

    error C2934: 'greater<char *>' : template-class-id redefined as a nested 'struct' of '<Unknown>'

    又是这个东西。。让我一直没有搞定。。网上也没找到相应的解决方案。

    今天突然发现了。。namespace的问题。因为greater是定义在std里面的。。
    汗啊。。感觉这报错好没提示性。。于是一改果然可以了。

    下面这份代码和前面的差不多。在VC6下运行正常:

    相信通过前面的解释能够很容易明白。

    #include <iostream>
    #include <list>
    #include <string.h>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    char *ss[] = { "bb" , "aa" , "cc" , "ee" , "dd" } ; 
    
    namespace std{
        struct greater<char*> : binary_function<char*, char*, bool> {
        bool operator()(const char*& _X, const char*& _Y) const
            {return (strcmp(_X,_Y) == -1); }
        };
    }
    
    int main(){
        list<char*> l(ss , ss + sizeof(ss) / sizeof(char*)) ;
        ostream_iterator<char*> oit(cout , " ") ;
        copy( l.begin() , l.end() , oit) ;cout<<endl;
        l.sort() ;
        copy( l.begin() , l.end() , oit) ;cout<<endl;
        l.sort(greater<char*>()) ;
        copy( l.begin() , l.end() , oit) ;cout<<endl;
        return 0 ;
    }

    binary_function:

    Note: This class has been deprecated in C++11.

    This is a base class for standard binary function objects.

    Generically, function objects are instances of a class with member function operator() defined. This member function allows the object to be used with the same syntax as a regular function call, and therefore its type can be used as template parameter when a generic function type is expected.

    In the case of binary function objects, this operator() member function takes two parameters.

    binary_function is just a base class, from which specific binary function objects are derived. It has no operator()member defined (which derived classes are expected to define) - it simply has three public data members that aretypedefs of the template parameters. It is defined as:

    1
    2
    3
    4
    5
    6
    template <class Arg1, class Arg2, class Result>
      struct binary_function {
        typedef Arg1 first_argument_type;
        typedef Arg2 second_argument_type;
        typedef Result result_type;
      };

    上面的greater不继承binary_function也可以正常运行。

    要想利用STL list 的sort,还有一种办法,直接在list元素类里面重载   bool operator < 也可以正常运行。

    转自:http://hplonline20100103.blog.163.com/blog/static/1361364342010040031155/

  • 相关阅读:
    2014年科研方面回顾之一
    Woodbury matrix identity
    任务太多,时间太少,GT凶猛,不留情面啊。。。
    Linux系统——inode和block
    Linux系统——系统安全及应用
    Linux系统——ACL权限控制及特殊权限
    Linux系统——引导过程与服务控制
    Linux系统——Raid磁盘阵列
    Linux系统——文件系统与LVM 逻辑
    Linux系统——sed命令
  • 原文地址:https://www.cnblogs.com/youxin/p/3794379.html
Copyright © 2011-2022 走看看