我很好奇为什么这段代码不起作用:
#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似乎不会影响任何事情。
我找到了三种方法来修复&#34;此
修复#1
环绕布尔运算符&lt; ...在命名空间std中如此:
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<);
这似乎是最优雅的解决方案。但是,我不明白为什么我必须明确告诉编译器使用我定义的运算符&lt;。
所以我想知道:
1)为什么会这样?难道不能找到我的实现并使用它吗?
2)&#34; fix&#34;是最好的?如果我找不到,你会推荐什么?
有什么想法吗?谢谢你的阅读!
答案 0 :(得分:-1)
你已经自己解决了这个问题
问题在于您的运营商&lt;函数不会覆盖默认的tuple :: operator&lt;,它们位于不同的名称空间
中所以,你的Fix#1和Fix#3都是很好的解决方案
修复#1将它们放入相同的命名空间使其覆盖正确,我认为是最好的方法