错误 C2914:排序函数无法识别要使用哪个版本的重载谓词

Error C2914: sort function unable to identify which version of an overloaded predicate to use

我最近开始尝试自学 C++,并且是董事会的新手。我创建了一个名为 permuted_index 的支柱,以及一个名为 perm_index 的 permuted_index 对象矢量。

我编写了一个名为 "stringCompare" 的重载谓词,用于与排序函数一起对字符串向量或 permuted_index 对象向量进行排序。但是,当我尝试 运行 我的程序出现错误 C2914 - 据我所知,这意味着排序函数无法识别要使用的 stringCompare 版本。

我已经看了好几天了,完全被难住了!我可以通过注释掉谓词的一个版本来强制我的程序工作,但我真的很想了解底层程序并希望得到任何帮助。我已经提供了我认为可以帮助任何人在下面查看此内容的所有内容,但如果您需要任何更多信息,请告诉我。

这是置换索引支柱;

struct permuted_index{

std::string word ;

std::vector<std::string>::size_type line ;
std::string::size_type position ; 

std::vector<std::string> full_line ;
std::vector<std::string> rotated_line ; 

std::string before_word ;
std::string after_word ; };

这是重载谓词;

#include <string>  
#include <vector> 
#include "split.h" 
#include "Permuted_index.h"

using std::string ; 
using std::vector ; 

bool stringCompare(const string& x, const string& y) {

vector<string> p ;
vector<string> q ; 

p = split(x) ; 
q = split(y) ; 

return p[0] < q[0] ;
}


bool stringCompare(const permuted_index& x, const permuted_index& y){

return x.rotated_line[0] < y.rotated_line[0] ; 
}

这是上面调用的split函数;

vector<string> split(const string& s) 
{
    vector<string> ret ;
    typedef string::size_type string_size ; 

    string_size i = 0 ; 

    while(i != s.size())
    {
    while(i != s.size() && isspace(s[i]))
    {
        ++i ;
    }

    string_size j = i ; 

    while(j != s.size() && !isspace(s[j]))
    {
        ++j ;
    }

    if(i != j)
    {
        ret.push_back(s.substr(i, j-i)) ;
        i = j ;
    }
}

return ret ;
}

我的 main() 程序中导致错误的行是;

sort(perm_index.begin(), perm_index.end(), stringCompare) ;

准确的错误信息是:

error C2914: 'std::sort' : cannot deduce template argument as function   argument is ambiguous

尝试以下方法

sort(perm_index.begin(), perm_index.end(), 
     static_cast<bool(*)( const permuted_index &, const permuted_index & )>(stringCompare) );

出于某种原因,使用强制转换对我来说似乎有点不确定。但这有效:

void foo(std::vector<permuted_index> &pi)
{
    using Compare = bool (*)(const permuted_index &, const permuted_index&);
    Compare cmp = stringCompare;
    std::sort(pi.begin(), pi.end(), cmp);
}

这声明了一个类型别名,Compare

在 C++ 11 之前,这是通过所谓的 typedef 完成的,如:

typedef bool (*Compare)(const permuted_index &, const permuted_index &);

这些都只是说 Compare 是一个函数的名称,它接受两个 permuted_index 对象和 return 一个 bool。 (从技术上讲,Compare 是指向函数的指针,但函数名称本身也是指针。)函数类型名称的 C/C++ 语法并不是最容易解析的语法,但如果您阅读 typedef 从内到外它以某种左右顺序("spiral" 规则)表示 Compare 是一个指针(星号),指向一个函数接受两个 permuted_index引用(右边包含引用声明的括号)和 returning bool)你可以找到 a nice SO description of these topics here and there are various tutorials on function pointer syntax (evidence in and of itself that it isn't the simplest aspect of C/C++) around the web, such as this article that explains the spiral rule.

无论如何,Compare 是一个函数的别名,该函数正是 sort 在对 permuted_index 对象进行排序时期望比较器使用的类型。然后我们声明一个指针实例 cmp 指向 stringCompare。编译器现在可以准确地知道 cmp 的类型,因此对于我们可以将哪个 stringCompare 分配给 cmp 没有歧义。

另外,cmp 是一个指针,你实际上可以写

Compare cmp = &stringCompare;

在 C++ 中,函数名称本身 "decays" 指向指向该函数的指针,因此这是多余的,我在示例中将其省略。

另一种方法是使用内联 lambda。 Lambda 是该语言的一个新部分,它允许您就地声明一个函数。对于调用算法时通常只使用一次的比较器之类的东西,这是一种非常有用的语法。与函数指针一样,语法需要一点时间来适应。 Here is a nice SO article on the subject. 基本上 [] 表示这是一个简单的 lambda(不是任何类型的 "closure"),后面是 lambda 的参数,然后是它的主体。 (您可以选择在参数之后立即将 return 类型声明为

[](const permuted_index &, const permuted_index &) -> bool { ... }

但这通常不是必需的,因为编译器可以从函数体中推断出类型。)

无论如何,与上面的 typedef 一样,这种方法有效,因为 lambda 已经声明了参数是什么,所以将选择正确的 stringCompare,并且 lambda 的类型是显而易见的编译器,因此不会混淆使用哪种函数类型来计算 sort.

中的第二个模板类型
void bar(std::vector<permuted_index> &pi)
{
    std::sort(pi.begin(), pi.end(), 
              [](const permuted_index &a, const permuted_index &b) 
              { return stringCompare(a,b); });
}

我认为问题在于 Compare 模板参数完全独立于被比较的类型 - 目前库无法指定其类型应具有比较签名在被排序的两种值类型之间。 (虽然我不确定为什么 SFINAE 不消除使用第一个重载的可能性。)