为什么 std::sort 找不到合适的(静态成员)函数重载?

Why does std::sort fail to find the appropriate (static member) function overload?

本文关键字:静态成员 函数 重载 sort std 找不到 为什么      更新时间:2023-10-16

我有一个类,它提供了可供std::sort使用的自定义静态比较器。以下内容可以很好地编译(简化为最小的代码示例(:

#include <vector>
#include <string>
#include <algorithm>
class StringUtils
{
public:
static bool customStringCompare(const std::string&, const std::string&) { return true; }
};
void test()
{
std::vector<std::string> testList;
std::sort(testList.begin(), testList.end(), StringUtils::customStringCompare);
}

现在,当我向 StringUtils 类添加重载时,例如

static bool customStringCompare(const char*, const char*) { return true; }

以下方法将起作用:

void test2()
{
std::string s1, s2;
StringUtils::customStringCompare(s1, s2);
}

但是,上面的std::sort调用会在 MSVC 2015 Update 2 中生成编译器错误 C2672(未找到匹配的重载(、C2780(预期的 2 个参数 - 支持 3 个(、C2783(无法推断"_Pr"的模板参数(。

为什么在这种情况下std::sort找不到匹配的重载?

在你的代码中,std::sort采用函数指针。那么编译器如何决定你想要哪个函数呢?智能感知显示以下错误:

无法确定重载函数StringUtils::customStringCompare的哪个实例

若要使用重载,可以将比较器转换为函数对象:

struct Comparator {
bool operator()(const std::string&, const std::string&) const {
return true;
}
bool operator()(const char*, const char*) const {
return true;
}
};
void test() {
std::vector<std::string> testList;
std::sort(testList.begin(), testList.end(), Comparator{});
}

或者,从 C++14 开始,您可以使用通用 lambda 函数:

void test() {
std::vector<std::string> testList;
std::sort(testList.begin(), testList.end(), 
[](const auto& s1, const auto& s2) {
return StringUtils::customStringCompare(s1, s2);
});
}

问题是有两个重载,将一个传递给std::sort并不能阐明应该使用哪个重载1.编译器无法从std::sort调用中的用法推断出这一点。这是有道理的:std::sort的比较器参数的类型只是一个模板参数,即它完全未指定:任何重载都与其他任何重载一样好。

有多种解决方法,在实践中,我通常建议传递一个函子,如 Evg 的答案所示。

但重要的是要了解错误只是由无法自动推断的类型引起的。因此,要使代码编译,显式指定类型就足够了;这将选择单个重载:

std::sort(
testList.begin(),
testList.end(),
static_cast<bool (*)(std::string const&, std::string const&)>(StringUtils::customStringCompare)
);

在这里,我们使用static_cast来显式指示函数(指针(的类型,以便解决重载问题。


1而且,坦率地说,每个主流编译器都会产生一条烂的错误消息。这早已为人所知,并且是完全可以修复的。clang++比GCC和MSVC略好,但老实说并没有太多。但即使是 C#,一种完全不相关的语言,在类似情况下也会给出非常特殊的错误。