自定义std::sort的比较函数时发生"invalid operator<"错误原因

本文探讨了VS2008中sort()函数使用时遇到的invalid operator<错误,并提供了正确的解决方法。同时,讨论了自定义比较函数应遵循的strict weak ordering原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VS2008的sort()函数的用法貌似挺郁闷的。。。

前些时候写了个sort的compare函数,错误"Expression : invalid operator <",baidu+google了一下,没有找到比较明确的说法,不过找到了微软的一个网页,说得算是很清楚,不过看得不太明白。意思大概是出这个错是因为VS2005,VS2008后的sort()里,用的是所谓的“ strict weak ordering”,也就是说,如果a==b,则返回的应该是false,如果返回的是true,则会出上面的错。

网页:http://support.microsoft.com/kb/949171

以下摘抄网页中的说法:

1.strict weak ordering

举例说明如下:

 


· Strict: pred(X, X) is always false.

· Weak: If !pred(X, Y) && !pred(Y, X), X==Y.

· Ordering: If pred(X, Y) && pred(Y, Z), then pred(X, Z).

2.出现"Expression : invalid operator <"的写法

bool CustPredicate (int elem1, int elem2 )
{
    if(elem1 > elem2)
        return true; 

    if (elem1 < elem2)
        return false;
    return true;
}

3.为了解决错误,应把以上代码改写为以下两种中的任一种:

(1)

bool CustPredicate (int elem1, int elem2 )
{
    if(elem1 > elem2)
        return true; 

    if (elem1 < elem2)
        return false;

    return false; //Should return false if both the vaules are same
}

(2)

Second Option:-
bool CustPredicate (int elem1, int elem2 )
{
    return elem1 > elem2;
}

 

Im using hgeVector in a std::map as the key. My Tile class is the value.

/** needed for sorting by vector in map */constbooloperator<( const hgeVector& a, const hgeVector& b ) { if ( a.x < b.x && a.y < b.y ) returntrue; if ( a.x > b.x && a.y > b.y ) returnfalse; return ( a.x < b.x || a.y < b.y ); } typedef std::map<hgeVector, Tile*> TileMap;



The problem arises when doing std::map[ position ] = new Tile( id );, the map asserts and gives the error "invalid operator<".

However, the first time I insert something into the map it works, but the second time, I get the assert. The first key I insert is (6,-3), which works, but the second one, (7,-4), asserts.

The plan with the operator is simple; if both x and y is less, a is less. Else, if neither is less, a is not less. Then the special case; if x or y has the same value, a is less if either is less.

Where is my misstake? 

0

Back to top of the page up there ^

Ad: Attend the Game/AI Conference June 23-24 #2     Gage64     MemberGroup:Members Reputation: 701

  Posted 10 June 2008 - 09:32 PM

I think this is because your operator< is faulty. For example, (6, -3) < (7, -4) and (7, -4) < (6, -3) both return true, but obviously that doesn't make sense.

You should reconsider what less-than means for vectors. Probably the best option would be a sort of lexicographic compare:

const bool operator<( const hgeVector& a, const hgeVector& b ){ return (a.x < b.x) || ( (a.x == b.x) && (a.y < b.y) );}
OOP Articles | C++: A Dialog (free book) | Thinking in C++ (free book) | Google Books - Free preview for many books Back to top of the page up there ^ #3     chairthrower     MemberGroup:Members Reputation: 224

  Posted 10 June 2008 - 09:32 PM


I havent got the raw brainpower to be able to trace through the logic - but this is the way I structure comparators which I find is fairly readble. we just test each dimension and whether we need another dimension to help resolve otherwise returning false.

const bool operator<( const hgeVector& a, const hgeVector& b )
{
if ( a.x != b.x) return a.x < b.x; // first dim
if ( a.y != b.y) return a.y < b.y; // second dim 
return false; // false in case of equality

Back to top of the page up there ^ #4     Mizipzor     MemberGroup:Members Reputation: 98

  Posted 10 June 2008 - 09:52 PM

Original post by Gage64 For example, (6, -3) < (7, -4) and (7, -4) < (6, -3) both return true, but obviously that doesn't make sense.


Very true indeed, I wonder how I couldnt spot that. :p

Anyways, both your snippets work, thanks and ++rating to you both! :)


Back to top of the page up there ^ #5     godecho     MemberGroup:Members Reputation: 90

  Posted 11 June 2008 - 03:18 AM

I'm just making a guess about the data types your vector holds, but remember there's something to  keep in mind  when performing equality tests on floats. Both of the solutions suggested here perform equality tests. They might be fine for your situation, but it's something that should be considered. 
Back to top of the page up there ^ #6     Sneftel     Moderator - Consoles, PDAs, and Cell PhonesGroup:Senior Moderators Reputation: 1077

  Posted 11 June 2008 - 03:43 AM

Original post by godecho
I'm just making a guess about the data types your vector holds, but remember there's something to  keep in mind  when performing equality tests on floats. Both of the solutions suggested here perform equality tests. They might be fine for your situation, but it's something that should be considered.

Actually, it isn't... or, at least, it doesn't turn out to matter. For all the vagaries of floating point math, trichotomy still holds true for real numbers in IEEE-754, and that's all that's needed here. Of course, the resultant ordering isn't going to be particularly coherent, but that's to be expected from any ℜ2→ℜ mapping. 
Back to top of the page up there ^ #7     chairthrower     MemberGroup:Members Reputation: 224

  Posted 11 June 2008 - 03:53 AM

Original post by godecho
I'm just making a guess about the data types your vector holds, but remember there's something to  keep in mind  when performing equality tests on floats. Both of the solutions suggested here perform equality tests. They might be fine for your situation, but it's something that should be considered.


Also mixing and matching == and < should probably not be considered good style given the distinction made in stl between the seperate concepts of equality and equivalence - sorry i cant find a good link but scott meyers covers it in  effective stl . However for a practical use case that is not generic and confined to floats types i dont think its an issue. 
Back to top of the page up there ^ #8     godecho     MemberGroup:Members Reputation: 90

  Posted 11 June 2008 - 06:10 AM

Original post by Sneftel
Actually, it isn't... or, at least, it doesn't turn out to matter. For all the vagaries of floating point math, trichotomy still holds true for real numbers in IEEE-754, and that's all that's needed here. Of course, the resultant ordering isn't going to be particularly coherent, but that's to be expected from any ℜ2→ℜ mapping.
#include <iostream> #include <vector> #include <algorithm> #include <sstream> #include <unordered_set> int main() { // 读取未到成员 std::unordered_set<int> excluded; std::cout << "请输入未到成员编号(1-55,多个用空格分隔): "<<std::endl; // 处理输入 std::string input; std::getline(std::cin, input); std::istringstream iss(input); // 初始化固定排除集合 const std::unordered_set<int> excluded = {4, 7, 11, 12, 22, 26, 49}; // 生成候选序列 std::vector<int> candidates; for (int i = 1; i <= 55; ++i) { if (!excluded.count(i)) { // 过滤排除数字[^1] candidates.push_back(i); } } std::unordered_set<int> excluded; std::cout << "请输入未到成员编号(1-55,多个用空格分隔): "; // 处理输入 std::string input; std::getline(std::cin, input); std::istringstream iss(input); int num; while (iss >> num) { if (num >= 1 && num <= 55) { excluded.insert(num); } else { std::cerr << "警告:忽略无效编号 " << num << " (超出范围)\n"; } } // 生成可用序列 std::vector<int> candidates; for (int i = 1; i <= 55; ++i) { if (!excluded.count(i)) { candidates.push_back(i); } } // 生成可用序列 std::vector<int> candidates; for (int i = 1; i <= 55; ++i) { if (!excluded.count(i)) { candidates.push_back(i); } } // 洗牌算法 std::random_device rd; std::mt19937 gen(rd()); std::shuffle(candidates.begin(), candidates.end(), gen); // 输出结果 std::cout << "随机顺序: "; for (const auto& n : candidates) { std::cout << n << " "; } return 0; } /* #include <iostream> #include <random> #include <chrono> using namespace std; int num[1000]; int l; void c(){ num[1]=7; num[2]=11; num[3]=12; num[4]=22; num[6]=26; num[8]=49; num[9]=4; l=9; } int sj(int a,int b){ random_device rd; mt19937 gen(rd()); uniform_int_distribution<> distrib(1, 55); int a=distrib(gen); for(int i=1;i<=l;i++){ if(s==num[i]) return sj(a,b); } } int main(){ cout<<" 这是一个选人程序,中途请勿关闭,关闭就会重置 "<<endl; cout<<" 每次请输入'1'来进行选人 输入'2'关闭(重置) "<<endl; int a; c(); cout<<" 请在下面输入请假学生学号: (输入'0'截止)"<<endl; while(cin>>a){ if(a==0){ break; }num[++l]=a; } while(cin>>a){ cout<<" 请等待... " << endl; if(a==2){ break; } int s=sj(1,55); cout<< "选中的'幸运儿'就是" << s << "号!!! 有请他/她上台 " << endl; } return 0; } #include <iostream> #include <vector> #include <algorithm> #include <unordered_set> int main() { // 洗牌算法 std::random_device rd; std::mt19937 gen(rd()); std::shuffle(candidates.begin(), candidates.end(), gen); // 输出结果 std::cout << "随机顺序: "; for (const auto& n : candidates) { std::cout << n << " "; } return 0; } */ 为何报错
05-29
这是我们课设目前的代码,接下来还需要:数据持久化 实现CSV读写 添加错误处理 设计数据验证,这些应该如何实现 // DateTime.h #pragma once #include <string> #include <ctime> #include <sstream> #include <iomanip> #include <iostream> // 日期类 class Date { private: int year, month, day; public: Date(int y = 0, int m = 0, int d = 0) : year(y), month(m), day(d) {} static Date fromString(const std::string& str) { if (str.empty()) return Date(); int y, m, d; char delim; std::stringstream ss(str); ss >> y >> delim >> m >> delim >> d; return Date(y, m, d); } std::string toString() const { std::stringstream ss; ss << std::setfill('0') << std::setw(4) << year << "-" << std::setw(2) << month << "-" << std::setw(2) << day; return ss.str(); } bool operator==(const Date& other) const { return year == other.year && month == other.month && day == other.day; } bool operator<(const Date& other) const { if (year != other.year) return year < other.year; if (month != other.month) return month < other.month; return day < other.day; } // 修复了 operator> 的实现 bool operator>(const Date& other) const { if (year != other.year) return year > other.year; if (month != other.month) return month > other.month; return day > other.day; } }; // 间类 class Time { private: int hour, minute; public: Time(int h = 0, int m = 0) : hour(h), minute(m) {} static Time fromString(const std::string& str) { if (str.empty()) return Time(); int h, m; char delim; std::stringstream ss(str); ss >> h >> delim >> m; return Time(h, m); } std::string toString() const { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << hour << ":" << std::setw(2) << minute; return ss.str(); } int toMinutes() const { return hour * 60 + minute; } bool operator==(const Time& other) const { return hour == other.hour && minute == other.minute; } bool operator<(const Time& other) const { return toMinutes() < other.toMinutes(); } bool operator>(const Time& other) const { return toMinutes() > other.toMinutes(); } }; // 间段类 class TimeRange { private: Time start, end; public: TimeRange(const Time& s = Time(), const Time& e = Time()) : start(s), end(e) {} static TimeRange fromString(const std::string& str) { if (str.empty()) return TimeRange(); size_t pos = str.find('-'); if (pos == std::string::npos) return TimeRange(); return TimeRange( Time::fromString(str.substr(0, pos)), Time::fromString(str.substr(pos + 1)) ); } std::string toString() const { return start.toString() + "-" + end.toString(); } bool overlaps(const TimeRange& other) const { return start < other.end&& end > other.start; } // 添加相等运算符重载 bool operator==(const TimeRange& other) const { return start == other.start && end == other.end; } }; // 考试间段 class ExamSlot { private: Date date; TimeRange time; public: ExamSlot(const Date& d = Date(), const TimeRange& t = TimeRange()) : date(d), time(t) {} static ExamSlot fromString(const std::string& str) { if (str.empty()) return ExamSlot(); size_t pos = str.find(' '); if (pos == std::string::npos) return ExamSlot(); return ExamSlot( Date::fromString(str.substr(0, pos)), TimeRange::fromString(str.substr(pos + 1)) ); } std::string toString() const { return date.toString() + " " + time.toString(); } bool conflictsWith(const ExamSlot& other) const { return date == other.date && time.overlaps(other.time); } // 添加相等运算符重载(修复了编译错误) bool operator==(const ExamSlot& other) const { return date == other.date && time == other.time; } }; // Teacher.h #include <vector> #include <string> #include <algorithm> class Teacher { private: std::string id; std::string name; std::vector<ExamSlot> assignedSlots; public: Teacher(const std::string& id = "", const std::string& name = "") : id(id), name(name) {} // 访问器 const std::string& getId() const { return id; } const std::string& getName() const { return name; } // 添加清除监考任务的方法 void clearAssignments() { assignedSlots.clear(); } // 添加监考任务 void assignExam(const ExamSlot& slot) { if (std::find(assignedSlots.begin(), assignedSlots.end(), slot) == assignedSlots.end()) { assignedSlots.push_back(slot); } } // 检查间段是否可用 bool isAvailable(const ExamSlot& slot) const { for (const auto& assigned : assignedSlots) { if (assigned.conflictsWith(slot)) { return false; } } return true; } // 统计监考次数 int totalProctorCount() const { return static_cast<int>(assignedSlots.size()); } // 序列化 std::string toString() const { return id + "," + name + "," + std::to_string(totalProctorCount()); } }; // Exam.h #include <vector> #include <string> #include <algorithm> class Exam { private: std::string courseCode; std::string courseName; ExamSlot slot; std::string location; int studentCount; std::vector<std::string> instructors; std::vector<std::string> proctors; public: Exam(const std::string& code = "", const std::string& name = "", const ExamSlot& slot = ExamSlot(), const std::string& loc = "", int students = 0) : courseCode(code), courseName(name), slot(slot), location(loc), studentCount(students) {} // 访问器 const std::string& getCourseCode() const { return courseCode; } const std::string& getCourseName() const { return courseName; } const ExamSlot& getSlot() const { return slot; } const std::string& getLocation() const { return location; } int getStudentCount() const { return studentCount; } // 添加清除监考教师的方法 void clearProctors() { proctors.clear(); } // 教师管理 void addInstructor(const std::string& teacher) { if (std::find(instructors.begin(), instructors.end(), teacher) == instructors.end()) { instructors.push_back(teacher); } } void addProctor(const std::string& teacher) { if (std::find(proctors.begin(), proctors.end(), teacher) == proctors.end()) { proctors.push_back(teacher); } } const std::vector<std::string>& getInstructors() const { return instructors; } const std::vector<std::string>& getProctors() const { return proctors; } // 检查教师身份 bool isInstructor(const std::string& teacher) const { return std::find(instructors.begin(), instructors.end(), teacher) != instructors.end(); } // 计算所需监考人数 int requiredProctors() const { return studentCount > 50 ? 3 : 2; } // 当前监考人数 int currentProctors() const { return static_cast<int>(proctors.size()); } // 序列化 std::string toString() const { std::string result = courseCode + "," + courseName + "," + slot.toString() + "," + location + "," + std::to_string(studentCount) + ","; // 添加任课教师 for (size_t i = 0; i < instructors.size(); ++i) { if (i > 0) result += ";"; result += instructors[i]; } result += ","; // 添加监考教师 for (size_t i = 0; i < proctors.size(); ++i) { if (i > 0) result += ";"; result += proctors[i]; } return result; } // 反序列化 static Exam fromString(const std::string& str) { std::vector<std::string> parts; std::stringstream ss(str); std::string item; while (std::getline(ss, item, ',')) { parts.push_back(item); } if (parts.size() < 7) return Exam(); Exam exam( parts[0], parts[1], ExamSlot::fromString(parts[2]), parts[3], std::stoi(parts[4]) ); // 解析任课教师 std::stringstream instructorsStream(parts[5]); while (std::getline(instructorsStream, item, ';')) { if (!item.empty()) exam.addInstructor(item); } // 解析监考教师 std::stringstream proctorsStream(parts[6]); while (std::getline(proctorsStream, item, ';')) { if (!item.empty()) exam.addProctor(item); } return exam; } }; // ProctorAssigner.h #include <vector> #include <algorithm> #include <random> #include <unordered_map> #include <climits> class ProctorAssigner { public: // 执行监考分配 void assign(std::vector<Exam>& exams, std::vector<Teacher>& teachers) { // 1. 按间排序考试 std::sort(exams.begin(), exams.end(), [](const Exam& a, const Exam& b) { return a.getSlot().toString() < b.getSlot().toString(); }); // 2. 重置所有监考分配 for (auto& teacher : teachers) { teacher.clearAssignments(); // 使用新添加的方法 } for (auto& exam : exams) { exam.clearProctors(); // 使用新添加的方法 } // 3. 准备教师映射 std::unordered_map<std::string, Teacher*> teacherMap; for (auto& teacher : teachers) { teacherMap[teacher.getName()] = &teacher; } // 4. 分配任课教师 assignInstructors(exams, teacherMap); // 5. 分配额外监考 assignAdditionalProctors(exams, teachers); } private: // 分配任课教师 void assignInstructors(std::vector<Exam>& exams, std::unordered_map<std::string, Teacher*>& teacherMap) { for (auto& exam : exams) { for (const auto& instructor : exam.getInstructors()) { auto it = teacherMap.find(instructor); if (it != teacherMap.end()) { Teacher* teacher = it->second; if (teacher->isAvailable(exam.getSlot())) { exam.addProctor(instructor); teacher->assignExam(exam.getSlot()); } } } } } // 分配额外监考 void assignAdditionalProctors(std::vector<Exam>& exams, std::vector<Teacher>& teachers) { // 创建随机数生成器 static std::mt19937 rng(std::random_device{}()); for (auto& exam : exams) { int needed = exam.requiredProctors() - exam.currentProctors(); while (needed > 0) { // 随机打乱教师顺序以确保均衡性 std::shuffle(teachers.begin(), teachers.end(), rng); Teacher* bestCandidate = nullptr; int minAssignments = INT_MAX; // 寻找最合适的教师 for (auto& teacher : teachers) { // 跳过任课教师 if (exam.isInstructor(teacher.getName())) continue; // 检查间冲突 if (!teacher.isAvailable(exam.getSlot())) continue; // 选择监考次数最少的教师 if (teacher.totalProctorCount() < minAssignments) { minAssignments = teacher.totalProctorCount(); bestCandidate = &teacher; } } // 如果没有可用教师,退出循环 if (!bestCandidate) break; // 分配监考 exam.addProctor(bestCandidate->getName()); bestCandidate->assignExam(exam.getSlot()); needed--; } } } }; // CsvHandler.h #include <fstream> #include <sstream> #include <vector> #include <string> class CsvHandler { public: // 加载考试数据 static std::vector<Exam> loadExams(const std::string& filePath) { std::vector<Exam> exams; std::ifstream file(filePath); if (!file.is_open()) { return exams; } std::string line; std::getline(file, line); // 跳过标题行 while (std::getline(file, line)) { if (line.empty()) continue; Exam exam = Exam::fromString(line); if (!exam.getCourseCode().empty()) { exams.push_back(exam); } } file.close(); return exams; } // 加载教师数据 static std::vector<Teacher> loadTeachers(const std::string& filePath) { std::vector<Teacher> teachers; std::ifstream file(filePath); if (!file.is_open()) { return teachers; } std::string line; std::getline(file, line); // 跳过标题行 while (std::getline(file, line)) { if (line.empty()) continue; std::stringstream ss(line); std::string id, name; std::getline(ss, id, ','); std::getline(ss, name); if (!id.empty() && !name.empty()) { teachers.push_back(Teacher(id, name)); } } file.close(); return teachers; } // 保存考试数据 static bool saveExams(const std::vector<Exam>& exams, const std::string& filePath) { std::ofstream file(filePath); if (!file.is_open()) { return false; } // 标题行 file << "课程代码,课程名称,考试间,地点,学生人数,任课教师,监考教师\n"; for (const auto& exam : exams) { file << exam.toString() << "\n"; } file.close(); return true; } // 保存统计数据 static bool saveStatistics(const std::vector<Teacher>& teachers, const std::string& filePath) { std::ofstream file(filePath); if (!file.is_open()) { return false; } // 标题行 file << "教师ID,教师姓名,总监考次数\n"; for (const auto& teacher : teachers) { file << teacher.toString() << "\n"; } file.close(); return true; } }; // main.cpp int main() { try { // 1. 加载数据 auto exams = CsvHandler::loadExams("all_exams.csv"); auto teachers = CsvHandler::loadTeachers("teachers.csv"); // 2. 筛选本系考试 std::string department = "计算机科学与技术系"; std::vector<Exam> deptExams; for (const auto& exam : exams) { // 根据实际数据结构实现筛选逻辑 // 示例:if (exam.getDepartment() == department)... deptExams.push_back(exam); } // 3. 执行监考分配 ProctorAssigner assigner; assigner.assign(deptExams, teachers); // 4. 保存结果 CsvHandler::saveExams(deptExams, "dept_exams.csv"); CsvHandler::saveStatistics(teachers, "statistics.csv"); std::cout << "监考分配完成!结果已保存到文件。" << std::endl; } catch (const std::exception& e) { std::cerr << "发生错误: " << e.what() << std::endl; return 1; } return 0; }
最新发布
06-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值