std::bind如何为std::sort绑定参数类型不同的二元比较操作?
问题1解答
std::bind没有做参数类型替换,它的核心逻辑是固定参数绑定+多余参数自动忽略:
你传入bind的原始lambda的第二个入参要求是std::string::size_type类型,你在调用bind时直接把固定值len绑定给了这个参数,后续调用bind生成的新可调用对象时,永远用这个预先绑定的len作为lambda的第二个入参,根本不会用到std::sort传入的第二个std::string类型参数,自然不存在类型转换/替换的问题。
问题2解答
你对“二元操作变一元”的理解是错误的:std::sort要求比较器是二元可调用对象,你用bind生成的对象本身确实支持接收两个参数,只是第二个传入的参数会被直接丢弃。
std::bind的规则是:调用bind生成的新对象时,传入的参数只会和bind参数列表里的占位符(_1/_2等)按顺序匹配,没有对应占位符的传入参数会被直接忽略。你在bind时只写了一个_1占位符,所以std::sort传入的第二个std::string参数没有占位符接收,直接被丢弃,不会传递给原始lambda。
问题3解答
我们可以把你例子里的执行逻辑拆解为以下几步:
- 你定义的原始lambda接收两个入参:第一个是
std::string const& str,第二个是std::string::size_type sz,返回值等价于str.size() >= sz。 - 调用
std::bind(lambda, std::placeholders::_1, len)时,会生成一个新的可调用对象,内部同时存储了lambda本身和固定值len,并且标记:新对象被调用时的第一个入参,会传递给原始lambda的第一个入参。 std::sort排序过程中需要比较两个元素a、b(均为std::string类型)时,会调用comp(a, b),其中comp就是你bind生成的可调用对象。- comp被调用时的内部逻辑:
- 取第一个入参
a,传给原始lambda的第一个参数str - 取预先绑定的固定值
len,传给原始lambda的第二个参数sz - 第二个入参
b没有对应占位符,直接丢弃 - 执行lambda,返回
a.size() >= len的布尔结果
- 取第一个入参
- 按照
std::sort的规则:如果comp(a,b)返回true,就把a排在b前面。所以只要a的长度大于等于5,不管b是什么,a都会排在b前面,最终恰好得到所有长字符串在前的结果。
补充说明
你后面给出的“把vector排到最前”的例子逻辑和上面完全一致:
你在bind时传入的参数是_1, std::string("vector"),所以每次std::sort调用comp(a,b)时,a会传给lambda的s1,固定值"vector"传给s2,b被直接丢弃,只要a == "vector"就返回true,所以"vector"会排在任意元素的前面,最终出现在序列开头。
注意:你的用法其实不符合
std::sort对比较器的严格弱序要求,只是恰好能得到分区效果,更规范的实现应该用std::partition,或者写符合要求的二元比较逻辑,比如:std::sort(vstr.begin(), vstr.end(), [len](const std::string& a, const std::string& b) { return (a.size() >= len) > (b.size() >= len); });
内容的提问来源于stack exchange,提问作者Itachi Uchiwa

