3

I was trying to use nested classes inside a template class. See the code snippet below:

template <class T>
class OutterTemplate {
public:
    class InnerBase {
    protected:
        const char* name_; 
    public:
        virtual void print() {
            cout << name_ << endl;
        } 

        void setName(const char* n) {
            name_ = n;
        }
    };

private:
    class Inner : public InnerBase {
        public:
            virtual void print() {
                cout << name_;
                cout << " and ";
                InnerBase::print();
            }
    };
public:    
    static InnerBase* getInner() {
        return new Inner();
    }
};

int main() {
    auto q = OutterTemplate<int>::getInner();
    q->setName("Not working");
    q->print();
}

I got error "error: 'name_' was not declared in this scope" when trying to compile this code. I have check if "outter" is not a template class, there is no such problem. Can anyone explain why this error with template classes and how to enable access to members of based class in case of nested classes inside template class?

  • 1
    You need `this->name_` – David G Feb 07 '14 at 20:18
  • @juanchopanza til, though I'm still not sure why the compiler could do that...it would have to define "Inner" as and InnerBase as dependent class names... – IdeaHat Feb 07 '14 at 21:03
  • @MadScienceDreams If it simpler if you ignore the outer class. Both `InnerBase` and `Inner` are class templates. – juanchopanza Feb 07 '14 at 21:18
  • @juanchopanza Yeah, couldn't the compiler just label all members of templates and classes derived from templates as dependent class names? It'd probably slow compilation down (it'd always have to look it up) but would prevent this weird issue. (I'm not disputing that it does it, btw, just that this is an interesting idiosyncrasy) – IdeaHat Feb 07 '14 at 21:22
  • Thanks for the answers. Indeed, add "this" solves the problem. But why need "this"? We don't need "this" for accessing members in normal (base) classes. – user3068202 Feb 09 '14 at 00:46

1 Answers1

2

The Standard is quite clear on this point:

14.6.2 Dependent names [temp.dep]

3 In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

Here, your OutterTemplate<T>::InnerBase is a dependent base class of OutterTemplate<T>::Inner, and cout << name_; involves unqualified name lookup. This means that InnerBase will not be examined. Adding this-> will remedy that:

14.6.2.1 Dependent types [temp.dep.type]

7 If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context.

Because this-> is a class member access expression, this means that name_ will be looked up at the point where OutterTemplate<T>::Inner is instantiated, at which point name_ will be found in the base class.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304