为什么当类在main()函数内部时,这个std::sort谓词会失败?

8
这是一个简单的示例,它说明了在外部声明class Predicate时的工作方式,但当完全相同的代码作为class InlinePredicate内联出现时,编译器无法匹配std::sort。奇怪的是,您可以将std::sort的第三个参数传递为任何(例如整数7),并且只有当不支持sort所需的operator()时才会出现编译错误。但当我传递下面的pred2时,它根本无法匹配:
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Predicate {
public:
    bool operator () (const pair<string,int>& a, const pair<string,int>& b)
    {
        return a.second < b.second;
    }
};

int
main()
{
    vector<pair<string, int> > a;

    Predicate pred;
    sort(a.begin(), a.end(), pred);

    class InlinePredicate {
    public:
        bool operator () (const pair<string,int>& a, const pair<string,int>& b)
        {
            return a.second < b.second;
        }
    } pred2;
    sort(a.begin(), a.end(), pred2);

    return 0;
}

repro.cc: 在函数 ‘int main()’ 中:

repro.cc:30: 错误:没有找到与‘sort(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, main()::InlinePredicate&)’相匹配的函数


1
作为一则附注:你的运算符应该是 const bool operator()(const pair<string,int>& a, const pair<string,int>& b) **const** - Martin York
2个回答

9

在C++03中,局部类没有链接,因此不能用作模板参数(§14.3.1/2)。

在C++0x中,这个限制已经被移除,你的代码可以原样编译。


1
你可能仍然应该使谓词运算符为const,因为sort可能需要。 - Kerrek SB
它可以在GCC 4.5上使用g++ -std=c++0x编译(不是4.3,而且我手头没有4.4) - Ben Jackson

5

在C++0x之前的版本中,函数内部声明的类不能出现在模板参数中。你调用了sort,它隐式地将模板参数设置为InlinePredicate,这是不合法的。

你可以考虑使用C++0x(在GCC中,传递--std=c++0x),在C++0x中,此代码将按原样工作,或者你可以使用匿名函数。另外,你也可以使用boost::lambda,使用boost::lambda,代码如下:

using namespace boost::lambda;

sort(a.begin(), a.end(), _1 < _2);

1
注意:自Boost 1.47起,Boost.Lambda已正式停用,Boost.Phoenix v3成为首选。因此,新代码最好使用Phoenix而不是Lambda(并且您展示的sort调用的语法将保持相同)。 - ildjarn
@ildjarn,哦太好了,又有一个C++03匿名函数的技巧要学习... :) - bdonlan
但是更加强大的,绝对值得。:-] 即使在 C++0x 中,我倾向于使用 Phoenix 函数对象而不是 C++0x lambda,因为它们是多态的,这种情况发生了一半的时间。 - ildjarn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接