繁体   English   中英

namespace std重载小于

[英]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;
}

据我所知,我只是创建一个intStrings向量,我的运算符应该首先按元组中的第二个元素排序,因此输出应该是(最后3行)

5 five
9 nine
2 two

无论如何在我的机器上运行它

2 two
5 five
9 nine

这意味着排序使用默认的小于运算符,忽略我指定的那个。 注意,在参数之前添加const似乎不会影响任何东西。

我发现了三种“修复”这种方法。

修复#1

环绕bool运算符<...在命名空间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)哪个“修复”最好? 如果我找不到的那个,你会推荐什么?

有任何想法吗? 谢谢阅读!

你的operator< overload在使用<的位置是不可见的(在std::sort的主体中和/或由它调用的任何辅助函数,在<algorithm>某处)。

如果要使用它,必须通过依赖于参数的查找来获取它; 但是std::tuple<int, std::string>中没有任何内容将全局命名空间作为关联的命名空间,因此ADL也没有帮助您,并且使用了标准命名空间。

将它作为比较器传递,最好使用lambda或函数对象(内联比函数指针更好),是最简单的修复。 我也建议重命名它; 具有与标准语义完全不同的语义的operator<重载,表达式a < b取决于表达式a < b可能使用也可能不使用,这不是一个好主意。

你已经自己解决了

问题是你的operator <function没有覆盖默认的tuple :: operator <,它们在不同的命名空间中

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM