help-gplusplus
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is it g++ bug with "typename"?


From: Grizlyk
Subject: Re: Is it g++ bug with "typename"?
Date: Sun, 11 Mar 2007 21:23:07 +0300

Paul Pluzhnikov wrote:
>
>> I am thinking: why if i will comment lines marked with '#' in the 
>> following
>> example, all will be compiled, else will not:
>
> You'll get better answers if you reduce your test case (or state
> that you couldn't).

I have posted complete compileable example and can not reduce it because can 
not detect the point of error, so I have posted all parts. I have marked 
probably error's line by "#" sign:

public:
    typedef c_Second                  Second;
    typedef typename c_Second::Third  Third; //#1
    typedef typename c_Second::Forth  Forth; //#2


>> 11.cpp:57: error: no type named 'Second' in 'class
>> 11.cpp:57: error: Pxx::Puser::First<int, unsigned int>'

It is really wrong error message of gcc due to "type named 'Second'" is 
declared in the class. My question was: why if I declare only

    typedef c_Second                  Second;

all will be OK? Is it standard behaviour (unexplainable for me) or it is gcc 
specific error? It is important for desing of my classes. If it is error and 
it is error in "Second::subtype" why gcc point to "Second", not to 
"Second::subtype"? It is really not easy to find a cause of the error 
looking for "Second".

***
By the way, i think we must not get any errors here, because all have been 
declared correctly, if we will trace compilation pass we will see the 
following:

1. class template Pxx::First declaration

namespace Pxx{
template <
          class Tobj,
          class c_Second,
          class Tuint=uint
         >
class First
{
public:
    typedef c_Second                  Second;
    typedef typename c_Second::Third  Third; //#1
    typedef typename c_Second::Forth  Forth; //#2


here "Second" will be used as forward declaration of the class name, no 
sizeof(Second) needed, so we even can compile here concrete code returning 
references to "Second" and so on, the name can not be resolved at the point 
of template declaration.

"typename c_Second::Third" is forward declaration of the class name, can not 
be resolved at the point of template declaration.

2. class template Pxx::Second declaration

namespace Pxx{
template <
          class Tobj,
          class c_First,
          class c_Forth,
          class c_Third,
          class Tuint=uint
         >
class Second
{
public:
    typedef c_First    First;
    typedef c_Forth    Forth;
    typedef c_Third    Third;

    //derived Second
    typedef typename c_First::Second c_Second;

here the same, "typename c_First::Second" is forward declaration of the 
class name, can not be resolved at the point of template declaration.


3. some classes forward declarations

namespace Puser{

template <class Tobj,class Tuint> class First;
template <class Tobj,class Tuint> class Second;
template <class Tobj,class Tuint> class Third;
template <class Tobj,class Tuint> class Forth;

here the same: "First<>" and "Second<>" are forward declarations of the 
class name, can not be resolved at the point of template declaration.

4. class template Puser::First declaration

template <
          class Tobj,
          class Tuint=uint
         >
class First:
    public Pxx::First<
                        Tobj,
                        Second<Tobj,Tuint>,
                        Tuint
                       >
{
    typedef Pxx::First<
                        Tobj,
                        Second<Tobj,Tuint>,
                        Tuint
                       >
            Tparent;

now
"typename Tparent::Second" is instantiated as "Second<Tobj,Tuint>"

>> 11.cpp:57: error: no type named 'Second' in 'class
>> 11.cpp:57: error: Pxx::Puser::First<int, unsigned int>'

What is the problem here? Nothing.

"typename Tparent::c_Second::Third" is still forward declaration of the 
class name, can not be resolved at the point of template Puser::First 
declaration, because we have no body of "Second<Tobj,Tuint>" here, only 
forward declaration of "Second<Tobj,Tuint>".

5. class template Puser::Second declaration

template <
          class Tobj,
          class Tuint=uint
         >
class Second:
    public Pxx::Second<
                            Tobj,
                            First<Tobj,Tuint>,
                            Forth<Tobj,Tuint>,
                            Third<Tobj,Tuint>,
                            Tuint
                           >
{
    typedef Pxx::Second<
                            Tobj,
                            First<Tobj,Tuint>,
                            Forth<Tobj,Tuint>,
                            Third<Tobj,Tuint>,
                            Tuint
                           >
            Tparent;

now

"typename Tparent::First" is instantiated as "First<Tobj,Tuint>"

"typename Tparent::First::Second" already _can_ be found during declaration 
of "Puser::Second" because we have already defined body of 
"First<Tobj,Tuint>" here: ("typename Tparent::Second" is instantiated as 
"Second<Tobj,Tuint>") so

"typename Tparent::First::Second" is well defined as "Second<Tobj,Tuint>" 
(as itself).


Beause "Second<Tobj,Tuint>" is self name, the name can be used not only as 
forward declaration of "Second<Tobj,Tuint>", but yet as name of "class with 
completely defined body", because compiler must allow "multipass" for 
class's types untill the class's "};" sign encountered. But in the example 
we do not need that, it is enough to treat the name as forward declaration 
of the class.

We also can write in "Pxx::Second" like this

    //subtype of derived Second
    typedef typename c_First::Second::First  c_Second_subtype_First;

and

"typename Tparent::c_Second_subtype_First" is
    "First<Tobj,Tuint>" (the same as "typename Tparent::First")


6. instance of Puser::First<int>

using Puser::First;
First<int>    test;

"typename Puser::First<int>::Tparent::Second" is
    "typename Puser::Second<int>"
"typename Puser::First<int>::Tparent::Third"  is
    "typename Puser::Second<int>::Third<int>"     //#1

"typename Puser::First<int>::Tparent::Fourth"  is
    "typename Puser::Second<int>::Fourth<int>"    //#2


All completely defined.

>
> The error message appears to be mis-leading.
> Here is what EDG parser reports:
>
> "junk.cc", line 57: error: incomplete type is not allowed
>      typedef typename c_First::Second c_Second;
>                       ^


It is interesting why "typename c_First::Second" is incomplete?

>          detected during:
>            instantiation of class "Pxx::Second<Tobj, c_First, c_Forth,
>                      c_Third, Tuint> [with Tobj=int,
>                      c_First=Pxx::Puser::First<int, uint>,
>                      c_Forth=Pxx::Puser::Forth<int, uint>,
>                      c_Third=Pxx::Puser::Third<int, uint>, Tuint=uint]" at
>                      line 106
>            instantiation of class "Pxx::Puser::Second<Tobj, Tuint> [with
>                      Tobj=int, Tuint=uint]" at line 14
>            instantiation of class "Pxx::First<Tobj, c_Second, Tuint> [with
>                      Tobj=int, c_Second=Pxx::Puser::Second<int, uint>,
>                      Tuint=uint]" at line 81
>            instantiation of class "Pxx::Puser::First<Tobj, Tuint> [with
>                      Tobj=int, Tuint=uint]" at line 141
>

What is "EDG parser"?


-- 
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new




reply via email to

[Prev in Thread] Current Thread [Next in Thread]