【问题标题】:Why does std::sort fail to find the appropriate (static member) function overload? [duplicate]为什么 std::sort 找不到合适的(静态成员)函数重载? [复制]
【发布时间】:2018-09-24 08:34:05
【问题描述】:

我有一个提供自定义静态比较器的类,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 更新 2 中产生编译器错误 C2672(未找到匹配的重载)、C2780(预期 2 个参数 - 支持 3 个)、C2783(无法推断“_Pr”的模板参数) .

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

【问题讨论】:

  • 您应该发布完整的错误消息,它说它无法推断模板参数(因为指向重载函数的指针不明确)。
  • @VTT 我更新了问题以包含所有三个错误代码。我没有发布完整的消息,因为它们是德语并且带有编译器的机器很遗憾没有连接到互联网。

标签: c++ visual-c++ stl overloading


【解决方案1】:

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

无法确定要使用哪个重载函数 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);
        });
}

【讨论】:

  • 我更喜欢函数对象解决方案,而不是链接问题中提供的任何解决方案:如果我除了比较器函数之外还提供这样的结构,则该类的用户不必关心类型扣除。这简化了调用者代码和单元测试,因此应该提供更高的可维护性和稳健性。
【解决方案2】:

问题是有两个重载,将一个传递给std::sort 并不能说明应该使用哪个重载1。编译器无法从 std::sort 调用中的用法推断出这一点。这是有道理的:The type of the comparator argument of 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#,一种完全不相关的语言,在类似情况下也会产生高度特殊的错误。

【讨论】:

  • 使用上面的静态转换我得到:无法从 'bool (__cdecl *)(const string &,const string &)' 转换为 'bool (__cdecl *)(const string &,const string & )' Visiul Studio 2017 社区
猜你喜欢
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多