jeanluc
jeanluc

Reputation: 1708

Not declared in scope - friend comparator class for priority_queue C++

First let me condense the relevant code, note the parameter movies which produces the error:

// ActorGraph.hpp
class ActorGraph
{
protected:
    class Movie; // definition further below
    friend class MovieYearComparator;

    int func(..., priority_queue<Movie, vector<Movie>, MovieYearComparator> &movies);

    class Movie {...};
};

In the implementation file we have:

// ActorGraph.cpp
class MovieYearComparator
{
public:
    bool operator() (const ActorGraph::Movie a, const ActorGraph::Movie b) const
    {
        // comparison operation
    }
};

ActorGraph::func(..., priority_queue<Movie, vector<Movie>, MovieYearComparator> &movies) 
{...}

However, g++ complains that MovieYearComparator was not declared in this scope, referring to the func declaration. I spelled everything correctly and this paradigm is working for other containers in the file, just not the priority queue. Note that Movie is a very small class and I therefore chose to pass it by value.

Upvotes: 3

Views: 866

Answers (1)

Holt
Holt

Reputation: 37616

When you forward-declare a class, you cannot do everything with it, you only have the right to use / store reference or pointer to it, e.g.:

struct A;

struct B {
    A *_a; // Ok
    B (A &a) : _a(&a) { } // Ok
};

void f (A a) { } // Oops!

The reason is simple: If you do not use a reference or a pointer, the compiler must know the size of the struct / class when using it.

In your case, priority_queue needs to use non-reference of the Comparer, but since the first time you instantiate the template (in the definition of ActorGraph) your Comparer (MovieYearComparator) is not a complete type, priority_queue cannot be instantiated.

You need to define the MovieYearComparator class before the first instantiation of your priority_queue, e.g.:

class ActorGraph {
protected:
    class Movie; // definition further below

    class MovieYearComparator
    {
    public:
        // Use reference since your forward-declare Movie
        bool operator() (const ActorGraph::Movie const& a, 
                         const ActorGraph::Movie const& b) const {
            // comparison operation
        }
    };

    int func(..., priority_queue<Movie, vector<Movie>, MovieYearComparator> &movies);

    class Movie {...};
};

If you want to keep your header "clean", you could only define the class in the header but implement the operator() in the cpp file:

class ActorGraph {
protected:
    class Movie; // definition further below

    struct MovieYearComparator {
        bool operator() (const ActorGraph::Movie const& a, 
                         const ActorGraph::Movie const& b) const;
    };

    int func(..., priority_queue<Movie, vector<Movie>, MovieYearComparator> &movies);

    class Movie {...};
};

// .cpp
bool ActorGraph::MovieYearComparator::operator() (const ActorGraph::Movie const& a, 
                                                  const ActorGraph::Movie const& b) const { }

Also note that since MovieYearComparator is now an inner class of ActorGraph, you do not need to make it a friend class.

Upvotes: 3

Related Questions