Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this std::sort predicate fail when the class is inside main()?

Tags:

c++

templates

stl

This is a much simplified repro which illustrates how class Predicate delcared outside main() works but when the exact code appears inline as class InlinePredicate the compiler can't match std::sort. The strange thing is that you can pass anything as the third argument to std::sort (say, integer 7) and you'll just get a compile error when it does not support the operator () that sort expects. But when I pass pred2 below it doesn't match at all:

#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: In function ‘int main()’:

repro.cc:30: error: no matching function for call to ‘sort(__gnu_cxx::__normal_iterator, std::allocator >, int>*, std::vector, std::allocator >, int>, std::allocator, std::allocator >, int> > > >, __gnu_cxx::__normal_iterator, std::allocator >, int>*, std::vector, std::allocator >, int>, std::allocator, std::allocator >, int> > > >, main()::InlinePredicate&)’

like image 871
Ben Jackson Avatar asked Jul 29 '11 23:07

Ben Jackson


2 Answers

In C++03, local classes have no linkage and consequently cannot be used as template arguments (§14.3.1/2).

In C++0x, this limitation has been removed and your code would compile as-is.

like image 117
ildjarn Avatar answered Nov 09 '22 12:11

ildjarn


In versions of C++ prior to C++0x, classes declared inside functions cannot appear in template parameters. Your invocation of sort implicitly instantiates it with a template parameter set to InlinePredicate, which is illegal.

You may want to consider using either C++0x (with GCC, pass --std=c++0x; in C++0x this code will work as-is, or you can use anonymous functions instead), or boost::lambda. With boost::lambda, it would look like this:

using namespace boost::lambda;

sort(a.begin(), a.end(), _1 < _2);
like image 20
bdonlan Avatar answered Nov 09 '22 14:11

bdonlan