C++ Migration Guide

Class Name Injection

The C++ standard says that the name of a class is "injected" into the class itself. This is a change from earlier C++ rules. Formerly, the name of the class was not found as a name within the class.

In most cases, this subtle change has no effect on an existing program. In some cases, this change can make a formerly valid program invalid, and sometimes can result in a change of meaning. For example:


const int X = 5;

class X {
    int i;
public:
    X(int j = X) : // what is the default value X?
        i(j) { }
};

To determine the meaning of X as a default parameter value, the compiler looks up the name X in the current scope, then in successive outer scopes, until it finds an X:

Because having a type and an object with the same name in the same scope is considered poor programming practice, this error should rarely occur. If you get such an error, you can fix the code by qualifying the variable with the proper scope, such as:


X(int j = ::X) 

The next example (adapted from the standard library) illustrates another scoping problem.


template class<T> class iterator { ... };

template class<T> class list {
     public:
       class iterator { ... };
       class const_iterator : public ::iterator<T> {
         public:
            const_iterator(const iterator&); // which iterator?
};

What is the parameter type to the constructor for const_iterator? Under the old C++ rules, the compiler does not find the name iterator in the scope of class const_iterator, so it searches the next outer scope, class list<T>. That scope has a member type iterator. The parameter type is therefore list<T>::iterator.

Under the new C++ rules, the name of a class is inserted into its own scope. In particular, the name of a base class is inserted into the base class. When the compiler starts searching for a name in a derived class scope, it can now find the name of a base class. Since the type of the parameter to the const_iterator constructor does not have a scope qualifier, the name that is found is the name of the const_iterator base class. The parameter type is therefore the global ::iterator<T>, instead of list<T>::iterator.

To get the intended result, you can change some of the names, or use a scope qualifier, such as:

const_iterator(const list<T>::iterator&);