命名空间std超载小于

namespace std overloading less than

本文关键字:小于 超载 std 命名空间      更新时间:2023-10-16

我很好奇为什么这件代码不起作用:

#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

环绕布尔操作员&lt;...在命名空间性标准中像这样:

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));
    }
}

但是,我被告知我们永远不应该在性病名称空间中添加东西,因为该行为不确定,所以这个修复程序似乎是最糟糕的。

修复#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));
}

(显然会添加垃圾:: desntmatter作为第三个make_tuple参数)但是,这似乎很简单,这似乎是很多工作。另外,由于没有有意义地使用枚举,这似乎很浪费。

修复#3

使用类似的谓词类似:

std::sort(v.begin(), v.end(), operator<);

这似乎是最优雅的解决方案。但是,我不明白为什么我必须明确告诉编译器使用我定义的操作员

所以我想知道:

1)为什么会发生这种情况?C 不应该找到我的实现吗?

2)哪个"修复"是最好的?如果我找不到那些,您会推荐什么?

有什么想法吗?感谢您的阅读!

在使用<的点上看不到您的operator<过载(在std::sort和/或IT所调用的任何辅助功能的正文中,<algorithm>中的某个地方)。

如果要使用,则必须通过参数依赖性查找来挑选;但是std::tuple<int, std::string>中没有任何包含全局名称空间作为关联名称空间的东西,因此ADL也不对您有帮助,并且使用了标准。

最简单的修复程序是将其作为比较器,最好使用lambda或函数对象(与函数指针更好)。我还建议将其重命名;具有与标准语义完全不同的语义的operator<超载,该语义可以根据表达式在何处而被表达式a < b使用,也不是一个好主意。

您已经通过自我修复了

问题是您的操作员&lt;函数不会覆盖默认元组::操作员,它们在不同的命名空间

所以,您的修复#1和Fix#3都是很好的解决方案

修复#1将它们放入相同的命名空间使其正确覆盖,我认为是最好的方法