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:

123456
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/

VC6.0 list sort出错,布布扣,bubuko.com

时间: 2024-10-07 06:47:20

VC6.0 list sort出错的相关文章

如何在VC6.0里存储带空格的字符串

char str[20]; cin.getline(str,20) 或 string str; getline(cin,str); 据说都可以存储含空格字符串,但我用VC6.0时都出错 以下为粘贴 关于在C++中输入带空格的字符串的方法 yibcs 2012-08-10 20:44:17 此人文章 #include <iostream> #include <stdio.h>#include <string> using namespace std; void main(

(转)VC6.0中OpenGL开发环境配置

首先简单介绍一下OpenGL: OpenGL作为当前主流的图形API之一,它在一些场合具有比DirectX更优越的特性.       OpenGL官方网站(英文)    http://www.opengl.org 然后设置编程的一些环境,及其安装必备文件的步骤如下: 第一步:选择一个编译环境 现在Windows系统的主流编译环境有Visual Studio,Broland C++ Builder,Dev-C++等,它们都是支持OpenGL的.但这里我们选择VC++ 6.0作为学习OpenGL的环

c++连接数据库 在vc6.0

配置相关环境 我的mysql安装路径为E:\mysql-5.5.28-win32所以要在VC中设置include路径和lib的路径. 添加MySql的include目录到VC工作台中Project->Settings->C/C++->Category->Preprocessor->Additional include directories中添加 E:\mysql-5.5.28-win32\include. 添加lib的路径:Tools->Options->Dir

VC6.0 编译生成Release或Debug版本

可以project->Set Active Config,选中release版本.此后,按F5或F7编译所得的结果就是release版本. -------------------------------------------------------- -------------------------------------------------------- vc6.0在设置选了win32 release,但是点了确定再打开设置,为什么又变成Win32 Debug了? 工程设置对话框中显示

VC++6.0打开文件出错的解决办法

1.下载http://support.microsoft.com/kb/241396里面的一个叫FileTool.exe的文件并解压,解压后是一个vc工程,用vc6.0打开工程,编译,得到FileTool.dll,把它拷到vc6.0安装目录下. 2.点vc菜单栏里面的Tools(工具)->Customizes(定制)->Add-ins and Macro Files(附加项和宏文件) 点 Browse(浏览),选择类型为*.dll, 找到刚刚那个FileTool.dll文件,点确定,vc界面上

VC6.0在Win10下的兼容性问题设置(可以试试)

Microsoft Visual C++ 6.0,简称VC6.0,是微软推出的一款C++编译器,将"高级语言"翻译为"机器语言(低级语言)"的程 序.Visual C++是一个功能强大的可视化软件开发工具.自1993年Microsoft公司推出Visual C++1.0后,随着其新版本的不断问 世,Visual C++已成为专业程序员进行软件开发的首选工具. VC++6.0主要是在Windows XP下运行,在win7,win8和win10下运行均会存在一些兼容性的

【转载】COM 组件设计与应用(九)——IDispatch 接口 for VC6.0

原文: http://vckbase.com/index.php/wv/1224.html 一.前言 终于写到了第九回,我也一直期盼着写这回的内容耶,为啥呢?因为自动化(automation)是非常常用.非常有用.非常精彩的一个 COM 功能.由于 WORD.EXCEL 等 OFFICE 软件提供了“宏”的功能,就连我们使用的VC开发环境也提供了“宏”功能,更由于 HTML.ASP.JSP 等都要依靠脚本(Script)的支持,更体现出了自动化接口的重要性. 如果你使用 vc6.0 的开发环境,

Visual C++ 6.0/VC6.0经典插件之源码窗口管理(Visual Booster )插件 安装图解

Visual Booster 是Visual C++ 6.0开发环境的辅助工具,使用该工具打开.cpp..h或者其他资源文件时会在左边及下边显示打开的窗口(并以后缀归类),查看源码的时候相当有用. 1.下载 Visual Booster  Visual Booster 下载地址:http://pan.baidu.com/s/1o6BTbV8 密码:vikq 2.安装 Visual Booster  下载之后解压文件,运行文件夹内的 "Visual Booster.exe" 进行安装.如

windows下vc6.0下的OpeSSL编译过程中的问题

我的机器环境是:window7 + vs2010 + vc6.0; 其实,在windows上用VS2010以上的工具来编译Openssl源码库很简单,估计大家都测试过,用VS2008及其以上的工具编译Openssl源码库就3行代码即可: perl Configure -WIN32 --prefix=d:/openssl ms\do_ms nmake -f ms\nt.mak vc6.0版本的openssl编译步骤如下: 1.打开命令提示符,找到vc6.0所在的bin目录,输入VCVARS32.B