草庐IT

c++ - 命名空间标准重载小于

coder 2024-02-04 原文

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

#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 vector ,我的运算符应该首先按元组中的第二个元素排序,因此输出应该是(最后 3 行)

5 five
9 nine
2 two

但是在我的机器上运行它我得到了

2 two
5 five
9 nine

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

我找到了三种“修复”这个问题的方法。

修复#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) 哪个“修复”最好?如果我没有找到,您会推荐什么?

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

最佳答案

你的 operator<< 处看不到过载被使用(在 std::sort 的主体中和/或它调用的任何辅助函数,在 <algorithm> 的某处)。

如果要使用它,必须通过依赖于参数的查找来获取它;但是std::tuple<int, std::string>里面什么都没有将全局命名空间作为关联的命名空间,因此 ADL 也无济于事,并且使用标准命名空间。

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

关于c++ - 命名空间标准重载小于,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30113926/

有关c++ - 命名空间标准重载小于的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  3. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  4. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  5. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. ruby-on-rails - 从应用程序中自定义文件夹内的命名空间自动加载 - 2

    我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty

  8. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

    Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby-on-rails - 没有参数的 `<<`(小于两倍)是什么意思? - 2

    我在一个我想在formtasticGem中覆盖的方法中找到了这个。该方法如下所示:defto_htmlinput_wrappingdohidden_field_html是什么意思?在第三行做什么?我知道它对数组有什么作用,但在这里我不知道。 最佳答案 你可以这样读:hidden_field_htmllabel_with_nested_checkbox是连接到hidden_​​field_html末尾的参数-为了“清晰”,他们将其分成两行 关于ruby-on-rails-没有参数的`

随机推荐