std :: reference_wrapper应该包含默认比较器"<"运算符吗?

VSO*_*low 9 c++ stl c++11 reference-wrapper

STL使用"小于"作为默认比较器.即使基础类定义了"<"运算符,对使用reference_wrapper <>包装的对象的STL比较器调用也不会编译.

看来,这是因为有没有隐式转换上所进行的上LHS所述的LHS.operator <(右轴),当它是一个成员函数.我已经确认使用免费版本作为比较器工作.

但是,如果reference_wrapper提供了"<"运算符,它在底层调用"<",则需要使用free函数.

我在reference_wrapper的代码中添加了以下内容(取自VS11 Beta xrefwrap.h),并且可以使用std :: map和我的reference_wrapper <>版本中包含的类,其中定义了"<"运算符.

    bool operator <(reference_wrapper<_Ty> const rhs) const {
    return this->get() < rhs.get();
}
Run Code Online (Sandbox Code Playgroud)

稍后添加:如果我理解正确,reference_wrapper <>提供与许多库所需的ptrs相关联的复制/分配语义,同时隐藏与ptr相关的语法.这允许使用引用类型语法,而不需要本地副本的开销.要将它与使用ptrs的示例进行比较,完全错过了reference_wrappers的一个要点:您希望避免使用ptr类型语法.

事情就是这样,当对象被包装在reference_wrappers中时,直接处理对象的代码会中断.不用说,"<"是默认的比较器,确实让它变得特别; 在很大比例的现有代码中,对象将定义这些以避免对特殊比较器的需求.

后来添加#2:此功能的历史表明,避免使用ptr语法不是最初的意图.然而,自推出首次推出以来已经过去了十年.由于大量新程序员"被引导" 以避免基于ptr的语法(毫无疑问受ptr免费语言的影响),如果它可以更加无缝地工作,特别是在处理在STL容器中存储对象的遗留代码时,该功能会变得越来越有用,并且价值全面复制.

稍后添加#3:使用最少的代码更改改进旧版代码 随着时间的推移,瘦类变得很重,容器中对象的大小也会增加.提高性能的一种快速方法是通过包装对象来避免副本.这将提供"C ptr"类型的性能,而无需额外的副本,只需对代码进行最小的更改.

std::map<const Object, string> objTable;
// can be rewritten as to avoid object copies using the
// __myOwn::reference_wrapper which contains the '<' operator
std::map<__myOwn::reference_wrapper<const Object>, string> rwTable_myOwn;

// which works with out any non-member free comparator functions
rwTable_myOwn[a]="One"; // Compiles and works

// When using the table with the std::reference_wrapper
std::map<std::reference_wrapper<const Object>, string> rwTable_std;
//the map does not work
rwTable_std[a]="One"; // Fails to compile it needs the custom non-member comparator
Run Code Online (Sandbox Code Playgroud)

GMa*_*ckG 9

不,它不应该.reference_wrapper除了将引用包装为值之外,做任何事都不是工作.

如果你需要比较两个reference_wrapper<T>(这不是一个参考T),那么你的工作就是完成它.出于同样的原因std::set<T*>,不会默认定义比较std::less<T>(*x, *y),也不应该是你的情况.包装器只是一个非空指针.

为什么要停在单个比较运算符或所有比较运算符?为什么不为所有标准函数重载参考包装?因为当解决方案如此简单时,它是不值得的.

  • @vsaxena:我认为`std :: [c] ref`和`std :: reference_wrapper`(或者更确切地说,它们的Boost对应物)最初是为`std :: thread`,`std :: bind`,` std :: async`等,它们需要传递给函数的参数的值语义,但用户不需要值语义(即副本).这实际上与指针与引用语义无关,而是让用户可以选择如何传递参数而不需要在用户或实现方面使用奇怪的恶作剧. (3认同)
  • 想象一下,如果`reference_wrapper`不存在.你想``bind`参数`heavy_object a;`到函数`void f(heavy_object const&)`.像`bind(f,a)`这样的普通调用会在对象`bind`中创建一个副本返回(这是唯一合理的默认值).您可以使用`bind(f,&a)`来存储指针,但现在`bind`对象不能再调用`f`,因为`f`不指望指针.默认情况下,您不能存储对参数的引用,因为您无法从中创建值,这可能比原始参数范围更长. (3认同)
  • @vsaxena:也读我的下一条评论,它不是关于"不使用指针",它是关于用户的自由选择,无论他们是否需要某些功能的价值或参考语义. (3认同)
  • @vsaxena :(回复你对问题的评论;放错地方?)如果不言自明,我就不需要问了.这是一个不好推理的标志,声称你想要的是真实的是不言而喻的(哦,多么巧合:你的立场恰恰是不言而喻的,完全没有偏见!).当然,它适用于"原始"对象,它们是被比较的对象.现在你不是在比较对象,而是在比较包装器.回答这个问题:什么时候一个包装纸"少"比另一个包装纸?这没有道理.不要试图实施毫无意义的事情. (2认同)
  • @vsaxena:你似乎认为,因为它已经10年了,现在是时候"继续前进"并做新事物了.为什么?它已经完成了10年,并且将继续做得恰好正如它所做的那样:将引用视为一个值.没有更多,没有更少.负担是*你*争论延长它.坦率地说,你做得很差.你唯一的论点似乎是"我真的希望我能让它完全符合我的要求,而且我总是知道什么是正确的,不言自明的".对不起,不行. (2认同)
  • @vsaxena`reference_wrapper`不是通用代理对象,虽然我发现它可以为代理创建一个很好的基类.它解决的问题是指定应该在`bind`对象中生成引用,如Xeo所提到的.你正在解决另一个问题,所以创建一个不同的类!或者使用常规指针.听起来你正在修复特定的错误,并希望语言简化手头的任务......它不会那样工作,如果你想尝试一些新的东西,你必须建立一些脚手架. (2认同)