inheriting from class of specialized self?

2019-02-24 06:41发布

问题:

Is this valid C++?

template<class category>
class any_iterator : public any_iterator<void>
{ 
public:
        typedef any_iterator<void> any_iter_void;

        any_iterator() : any_iter_void() {}
};
template<>
class any_iterator<void>
{ 
public:
        typedef any_iterator<void> any_iter_void;

        any_iterator() {}
        void foo() {};
};

int main() {
    any_iterator<int> a;
    a.foo();
}

MSVC10 accepts it with no errors/warnings on \WALL, but gcc-4.5.1 complains:

prog.cpp:3:5: error: invalid use of incomplete type 'class any_iterator'
prog.cpp:2:11: error: declaration of 'class any_iterator'
prog.cpp: In function 'int main()':
prog.cpp:21:11: error: 'class any_iterator' has no member named 'foo'
prog.cpp: In constructor 'any_iterator::any_iterator() [with category = int]':
prog.cpp:20:27: instantiated from here
prog.cpp:7:44: error: type 'any_iterator' is not a direct base of 'any_iterator'

Can someone quote the standard showing if this should or should not compile? I think this is a bug in MSVC.

As a note, I know the correct thing to do is to declare the class, specialize the root, then define the general case, and that's what I'll do to my code, but I was wondering which compiler is wrong here?

回答1:

To inherit from a type, that type must be complete. A little rearranging solves things:

template<class category>
class any_iterator;

template<>
class any_iterator<void>
{ 
public:
    typedef any_iterator<void> any_iter_void;

    any_iterator() { }
    void foo() { }
};

template<class category>
class any_iterator : public any_iterator<void>
{ 
public:
    typedef any_iterator<void> any_iter_void;

    any_iterator() : any_iter_void() { }
};

int main()
{
    any_iterator<int> a;
    a.foo();
}

Token standard quotes:

C++11, §10/2:

The type denoted by a base-type-specifier shall be a class type that is not an incompletely defined class; this class is called a direct base class for the class being defined.

§9.2/2:

A class is considered a completely-defined object type (or complete type) at the closing } of the class-specifier.



回答2:

10/2:

The type denoted by a base-type-specifier shall be a class type that is not an incompletely defined class

It is one manifestation of the bug of MSVC: its lack of two-phase name resolution.