2

I am trying to implement a priority queue. This is the code for the interface class:

template<typename TYPE, typename COMP_FUNCTOR = std::less<TYPE>>
class priority_queue {
public:
    typedef unsigned size_type;

    virtual ~priority_queue() {}    // impleted but does nothing, this is not a pure virtual function

    virtual void fix() = 0;

    /* some other methods*/

protected:
    COMP_FUNCTOR compare;

};

And the code that causes problem:

template<typename TYPE, typename COMP_FUNCTOR = std::less<TYPE>>
class sorted_priority_queue : public priority_queue<TYPE, COMP_FUNCTOR> {
public:
    typedef unsigned size_type;

    template<typename InputIterator>
    sorted_priority_queue(InputIterator start, InputIterator end, COMP_FUNCTOR comp = COMP_FUNCTOR());

    /* some other methods*/

private:
    std::vector<TYPE> data;
};

template<typename TYPE, typename COMP_FUNCTOR>
template<typename InputIterator>
sorted_priority_queue<TYPE, COMP_FUNCTOR>::sorted_priority_queue(
    InputIterator start, InputIterator end, COMP_FUNCTOR comp) {
    for(auto it = start; it != end; ++it) {
        data.push_back(*it);
    }
    fix();
    this->compare = comp;  // <--- the line that causes problem
}

When I tried to do compare = comp at the last line, it says "use of undeclared identifier 'compare'" and I must declare this-> in order to access compare, which is a protected member variable defined in the interface class, why? Thank you.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
ldytmac
  • 83
  • 6

1 Answers1

3

This has to do with how name lookups are performed in C++ template classes. The actual mechanism is a bit tricky, but essentially, when the compiler first sees a template class, it tries to resolve all of the names that it can without using the template arguments. In this case, it means that when it sees the name compare used without the this-> prefix, the compiler expects that compare refers to something that can be found without any prior knowledge of the template arguments. Unfortunately, in your case, the compiler can't figure out what compare refers to without knowing the template arguments because compare is stored in the base class, which depends on the template parameters. As a result, it doesn't look inside the base class when trying to figure out what compare refers to, hence the error.

If you explicitly write this->compare, on the other hand, the compiler knows that compare is a member of the class and will defer looking up what name it refers to until the point where the template arguments are actually made available.

This is one of the few cases in the language where this sort of error actually comes up, and as a good rule of thumb, if you're accessing

  1. something in a base class,
  2. in a template class,
  3. that inherits from something depending on a template argument,

then you're going to need to use the this-> prefix to avoid this issue.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • One is initially inclined to say this sounds like a poor compiler implementation or poor template design standard. But, then, I've never written a C++ compiler... or a C++ design standard. – GreatAndPowerfulOz Jul 22 '16 at 22:50
  • @Great.And.Powerful.Oz This is actually required according to the spec. In fact, it's the *bad* compilers that are the ones that won't do this properly. I suspect that the reason the spec does things this way is to let one-pass compilers build as much of the AST as possible during parsing and then go back to fill in types as necessary without having to reparse the code every time. If so, it's a necessary consequence of "C++ supports one-pass compilation" and "C++ has templates," and it's the best compromise. – templatetypedef Jul 22 '16 at 22:52
  • oh agreed. I was just making the statement from a naive point of view. BTW, it might be good to mention that one could also use a `using` statement to make the name dependent on the template parameters. That might make it more palatable than using `this->` – GreatAndPowerfulOz Jul 22 '16 at 23:09
  • @templatetypedef thank you, it is very helpful – ldytmac Jul 22 '16 at 23:37