#include "stdafx.h"
#include <iostream>
#include <tuple>
#include <string>
#include <vector>
#include <algorithm>
typedef std::tuple<int, std::string> intString;
bool operator<(intString& lhs, intString& rhs){
return std::tie(std::get<1>(lhs), std::get<0>(lhs)) < std::tie(std::get<1>(rhs), std::get<0>(rhs));
}
void printIntStrings(std::vector<intString>& v){
for (intString& i : v){
std::cout << std::get<0>(i) << " is " << std::get<1>(i) << std::endl;
}
}
int main(int argc, char* argv[])
{
std::vector<intString> v;
v.push_back(std::make_tuple(5, "five"));
v.push_back(std::make_tuple(2, "two"));
v.push_back(std::make_tuple(9, "nine"));
printIntStrings(v);
std::sort(v.begin(), v.end());
printIntStrings(v);
return 0;
}
据我所理解,我需要创建一个intStrings的向量,然后我的操作员应该首先按元组中的第二个元素进行排序,因此输出应该是(无论如何是最后3行)。
5 five
9 nine
2 two
然而,在我的电脑上运行它,我得到了
2 two
5 five
9 nine
这意味着排序正在使用默认的小于运算符,忽略我指定的运算符。请注意,将const添加到参数之前似乎没有影响。
我找到了三种“修复”方法。
修复方法1:
在std命名空间中包围bool operator< ...,如下所示:
namespace std{
bool operator<(intString& lhs, intString& rhs){
return std::tie(std::get<1>(lhs), std::get<0>(lhs)) < std::tie(std::get<1>(rhs), std::get<0>(rhs));
}
}
然而我被告知我们不应该向std命名空间中添加东西,因为这种行为是未定义的,所以这个修复方法似乎是最糟糕的。
修复方法 #2
像这样向元组中添加一些自定义内容:
enum class TRASH{DOESNTMATTER};
typedef std::tuple<int, std::string, TRASH> intString;
bool operator<(intString& lhs, intString& rhs){
return std::tie(std::get<1>(lhs), std::get<0>(lhs)) < std::tie(std::get<1>(rhs), std::get<0>(rhs));
}
(并且很明显需要将TRASH :: DOESNTMATTER添加为第三个make_tuple参数)但是,针对如此简单的事情看起来需要付出很多工作。此外,由于枚举未被有意义地使用,因此似乎是浪费的。
修复方法 #3
使用谓词排序,如下所示:
std::sort(v.begin(), v.end(), operator<);
这似乎是最优雅的解决方案。然而,我不明白为什么我必须显式地告诉编译器使用我定义的operator<。
所以我想知道:
1)为什么会发生这种情况?C++难道不能找到我的实现并使用它吗?
2)哪种“修复”方法最好?如果我找不到任何一种,你会推荐哪种?
有什么想法吗?感谢您的阅读!
operator<
更匹配,因为它的参数是const
。 - Oktalistoperator<
,所以编译器使用官方的而不是你的hack。 - Mooing Duck