命名空间标准重载小于
namespace std overloading less than
我很好奇为什么这段代码不起作用:
#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;
}
据我所知,我只是创建了一个 intString 向量,我的运算符应该首先按元组中的第二个元素排序,因此输出应该是(最后 3 行)
5 five
9 nine
2 two
但是 运行 它在我的机器上得到
2 two
5 five
9 nine
这意味着排序使用默认的小于运算符,忽略我指定的那个。请注意,在参数前添加 const 似乎没有任何影响。
我找到了三种方法 "fix" 这个。
修复#1
surround bool operator< ... 在命名空间 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<);
这似乎是最优雅的解决方案。但是,我不明白为什么我必须明确告诉编译器使用我定义的运算符<.
所以我想知道:
1) 为什么会这样? c++ 不应该找到我的实现并使用它吗?
2) 哪个 "fix" 最好?如果我找到 none 个,你会推荐什么?
有什么想法吗?感谢阅读!
你已经自己修好了
问题是你的运算符<函数没有覆盖默认的tuple::operator<,它们在不同的命名空间
所以,您的 Fix#1 和 Fix#3 都是很好的解决方案
Fix#1 将它们放入同一个命名空间使其覆盖正确,我认为这是最好的方法
你的 operator<
重载在使用 <
的地方是不可见的(在 std::sort
and/or 它调用的任何辅助函数的主体中,在 <algorithm>
) 的某处。
如果要使用,必须通过argument-dependent lookup来获取;但是 std::tuple<int, std::string>
中没有任何内容将全局命名空间作为关联的命名空间,因此 ADL 也无济于事,使用的是标准命名空间。
将其作为比较器传递,最好使用 lambda 或函数对象(内联比函数指针更好),这是最简单的解决方法。我还建议重命名它;具有与标准语义完全不同的语义的 operator<
重载,表达式 a < b
可能会或可能不会使用它取决于该表达式的位置,这不是一个好主意。
我很好奇为什么这段代码不起作用:
#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;
}
据我所知,我只是创建了一个 intString 向量,我的运算符应该首先按元组中的第二个元素排序,因此输出应该是(最后 3 行)
5 five
9 nine
2 two
但是 运行 它在我的机器上得到
2 two
5 five
9 nine
这意味着排序使用默认的小于运算符,忽略我指定的那个。请注意,在参数前添加 const 似乎没有任何影响。
我找到了三种方法 "fix" 这个。
修复#1
surround bool operator< ... 在命名空间 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<);
这似乎是最优雅的解决方案。但是,我不明白为什么我必须明确告诉编译器使用我定义的运算符<.
所以我想知道:
1) 为什么会这样? c++ 不应该找到我的实现并使用它吗?
2) 哪个 "fix" 最好?如果我找到 none 个,你会推荐什么?
有什么想法吗?感谢阅读!
你已经自己修好了
问题是你的运算符<函数没有覆盖默认的tuple::operator<,它们在不同的命名空间
所以,您的 Fix#1 和 Fix#3 都是很好的解决方案
Fix#1 将它们放入同一个命名空间使其覆盖正确,我认为这是最好的方法
你的 operator<
重载在使用 <
的地方是不可见的(在 std::sort
and/or 它调用的任何辅助函数的主体中,在 <algorithm>
) 的某处。
如果要使用,必须通过argument-dependent lookup来获取;但是 std::tuple<int, std::string>
中没有任何内容将全局命名空间作为关联的命名空间,因此 ADL 也无济于事,使用的是标准命名空间。
将其作为比较器传递,最好使用 lambda 或函数对象(内联比函数指针更好),这是最简单的解决方法。我还建议重命名它;具有与标准语义完全不同的语义的 operator<
重载,表达式 a < b
可能会或可能不会使用它取决于该表达式的位置,这不是一个好主意。