typenames in self-referential templates

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Anthony Heading

    typenames in self-referential templates

    Hi all,
    I've often found myself wanting to write code like the example here.
    Since
    both MSVC and gcc both reject it, I suspect it is indeed illegal.

    gcc: no type named `Name' in `class Collection<Anim al>'
    msvc7: error C2039: 'Name' : is not a member of 'Collection<Tra its>'

    But to me it seems pretty unambiguous, so I can't see why it's wrong.
    Could anybody give me a pointer, either to the standard or the basic
    rationale why it's an error?

    Thanks

    Anthony


    template <class T>
    class Animal
    {
    typename T::Name name; // This seems to be an ERROR
    };

    template <
    template <class> class Traits[color=blue]
    >[/color]
    class Collection :
    public Traits < Collection<Trai ts> >
    {
    public:
    typedef char* Name;
    };

    int main()
    {
    Collection<Anim al> zoo;
    return 0;
    }


  • David B. Held

    #2
    Re: typenames in self-referential templates

    "Anthony Heading" <anthony@magix. com.sg> wrote in message
    news:bkscqb$ql0 $1@catv02.starc at.ne.jp...[color=blue]
    > [...]
    > template <class T>
    > class Animal
    > {
    > typename T::Name name; // This seems to be an ERROR
    > [...][/color]

    Should there be a typedef in there somewhere? I wasn't aware
    that 'typename' was allowed to start a declaration.

    Dave


    Comment

    • Gianni Mariani

      #3
      Re: typenames in self-referential templates

      David B. Held wrote:[color=blue]
      > "Anthony Heading" <anthony@magix. com.sg> wrote in message
      > news:bkscqb$ql0 $1@catv02.starc at.ne.jp...
      >[color=green]
      >>[...]
      >>template <class T>
      >>class Animal
      >>{
      >> typename T::Name name; // This seems to be an ERROR
      >>[...][/color]
      >
      >
      > Should there be a typedef in there somewhere? I wasn't aware
      > that 'typename' was allowed to start a declaration.[/color]

      typename is used as a way to make templates unambiguous.

      without typename the code would look like:

      T::Name name;

      A declaration is

      TYPE <DECL> ;

      However there is no way for the compiler to know that T::Name is a type.

      So "typename T::Name" is a way of indicating that it IS a type.

      Comment

      • Gianni Mariani

        #4
        Re: typenames in self-referential templates

        Anthony Heading wrote:[color=blue]
        > Hi all,
        > I've often found myself wanting to write code like the example here.
        > Since
        > both MSVC and gcc both reject it, I suspect it is indeed illegal.
        >
        > gcc: no type named `Name' in `class Collection<Anim al>'
        > msvc7: error C2039: 'Name' : is not a member of 'Collection<Tra its>'
        >
        > But to me it seems pretty unambiguous, so I can't see why it's wrong.
        > Could anybody give me a pointer, either to the standard or the basic
        > rationale why it's an error?
        >[/color]

        The code below does not compile.

        Try posting the code you really intended to.
        [color=blue]
        >
        > template <class T>
        > class Animal
        > {
        > typename T::Name name; // This seems to be an ERROR
        > };
        >
        > template <
        > template <class> class Traits
        >
        > class Collection :
        > public Traits < Collection<Trai ts> >
        > {
        > public:
        > typedef char* Name;
        > };
        >
        > int main()
        > {
        > Collection<Anim al> zoo;
        > return 0;
        > }
        >
        >[/color]

        Comment

        • WW

          #5
          Re: typenames in self-referential templates

          Gianni Mariani wrote:[color=blue]
          > Anthony Heading wrote:[color=green]
          >> Hi all,
          >> I've often found myself wanting to write code like the example
          >> here. Since
          >> both MSVC and gcc both reject it, I suspect it is indeed illegal.
          >>
          >> gcc: no type named `Name' in `class Collection<Anim al>'
          >> msvc7: error C2039: 'Name' : is not a member of 'Collection<Tra its>'
          >>
          >> But to me it seems pretty unambiguous, so I can't see why it's wrong.
          >> Could anybody give me a pointer, either to the standard or the basic
          >> rationale why it's an error?
          >>[/color]
          >
          > The code below does not compile.
          >
          > Try posting the code you really intended to.[/color]

          Great God! He posted the code to ask why doesn't it compile!!!

          --
          WW aka Attila


          Comment

          • Mike Wahler

            #6
            Re: typenames in self-referential templates


            "Gianni Mariani" <gi2nospam@mari ani.ws> wrote in message
            news:bksjv1$45b @dispatch.conce ntric.net...[color=blue]
            > David B. Held wrote:[color=green]
            > > "Anthony Heading" <anthony@magix. com.sg> wrote in message
            > > news:bkscqb$ql0 $1@catv02.starc at.ne.jp...
            > >[color=darkred]
            > >>[...]
            > >>template <class T>
            > >>class Animal
            > >>{
            > >> typename T::Name name; // This seems to be an ERROR
            > >>[...][/color]
            > >
            > >
            > > Should there be a typedef in there somewhere? I wasn't aware
            > > that 'typename' was allowed to start a declaration.[/color]
            >
            > typename is used as a way to make templates unambiguous.
            >
            > without typename the code would look like:
            >
            > T::Name name;
            >
            > A declaration is
            >
            > TYPE <DECL> ;
            >
            > However there is no way for the compiler to know that T::Name is a type.
            >
            > So "typename T::Name" is a way of indicating that it IS a type.[/color]

            Also, note that in some contexts, it's not ambiguous
            at all what the type is, but the language rules still
            demand a 'typename' keyword.

            -Mike


            Comment

            • Shane Beasley

              #7
              Re: typenames in self-referential templates

              "Anthony Heading" <anthony@magix. com.sg> wrote in message news:<bkscqb$ql 0$1@catv02.star cat.ne.jp>...
              [color=blue]
              > template <class T>
              > class Animal
              > {
              > typename T::Name name; // This seems to be an ERROR
              > };
              >
              > template <
              > template <class> class Traits[color=green]
              > >[/color]
              > class Collection :
              > public Traits < Collection<Trai ts> >
              > {
              > public:
              > typedef char* Name;
              > };[/color]

              Collection<Anim al> depends on Animal<Collecti on> (via inheritance),
              but Animal<Collecti on> depends on Collection<Anim al> (via T::Name).
              Can't do that.
              [color=blue]
              > int main()
              > {
              > Collection<Anim al> zoo;
              > return 0;
              > }[/color]

              Collection's template parameter is called Traits, but Animal isn't a
              traits class -- it's the type of element stored in the Collection.
              You're actually using Collection as a traits class for Animal, except
              that Collection is defined in terms of Animal. Of course, it doesn't
              make sense for a contained type to depend on the definition of its
              container, anyway.

              Perhaps there should be a third class with traits for Animal, such
              that Collection< Animal<Traits> > would be used instead. More likely,
              Animal should either have a hardcoded Name type, or it should be some
              kind of global (or scoped) typedef -- are you really going to use
              Animals with different types of Name in your program?

              - Shane

              Comment

              • David B. Held

                #8
                Re: typenames in self-referential templates

                "Gianni Mariani" <gi2nospam@mari ani.ws> wrote in message
                news:bksjv1$45b @dispatch.conce ntric.net...[color=blue]
                > David B. Held wrote:[color=green]
                > > "Anthony Heading" <anthony@magix. com.sg> wrote in message
                > > news:bkscqb$ql0 $1@catv02.starc at.ne.jp...
                > >[color=darkred]
                > >>[...]
                > >>template <class T>
                > >>class Animal
                > >>{
                > >> typename T::Name name; // This seems to be an ERROR
                > >>[...][/color]
                > >
                > >
                > > Should there be a typedef in there somewhere? I wasn't aware
                > > that 'typename' was allowed to start a declaration.[/color]
                >
                > typename is used as a way to make templates unambiguous.
                >
                > without typename the code would look like:
                >
                > T::Name name;
                > [...][/color]

                Ah. Usually, people typedef dependent names, so I've never seen
                typename used in a declaration before.

                Dave


                Comment

                • Anthony Heading

                  #9
                  Re: typenames in self-referential templates


                  "Shane Beasley" <sbeasley@cs.ui c.edu> wrote in message
                  news:2f2d78e1.0 309241513.62c5e 405@posting.goo gle.com...[color=blue]
                  > Collection<Anim al> depends on Animal<Collecti on> (via inheritance),
                  > but Animal<Collecti on> depends on Collection<Anim al> (via T::Name).
                  > Can't do that.[/color]

                  So I infer... but the rationale escapes me. Consider for contrast the code
                  attached below, which _does_ run fine.
                  It seems that function names are allowed to have such a circular dependency
                  in templates, but not types.
                  Why fundamentally is this OK, but the types are a no-can-do?
                  [color=blue]
                  > Perhaps there should be a third class with traits for Animal, such
                  > that Collection< Animal<Traits> > would be used instead. More likely,
                  > Animal should either have a hardcoded Name type, or it should be some
                  > kind of global (or scoped) typedef -- are you really going to use
                  > Animals with different types of Name in your program?[/color]

                  I am. Obviously this is somewhat of a toy example, but one could imagine
                  Asian animals whose
                  Names are wchar_t. Clearly these would have need a Collection zoo of their
                  own, since the
                  type signature is different, but yes I could have both in the same program.

                  With a real program, I have templates mixed into a single class, and I just
                  find it puzzling
                  that the _functions_ can happily cross-call each other by passing in the
                  aggregate class as
                  a template param to its constituents, but the _types_ cannot be used that
                  way.

                  Rgds

                  Anthony

                  #include <iostream>

                  template <class T>
                  class Animal
                  {
                  public:
                  Animal() {
                  std::cout << T::something() << std::endl;
                  }
                  };

                  template <
                  template <class> class Traits[color=blue]
                  >[/color]
                  class Collection :
                  public Traits < Collection<Trai ts> >
                  {
                  public:
                  typedef char* Name;
                  static Name something() {
                  return (Name) "Menagerie" ;
                  }
                  };

                  int main()
                  {
                  Collection<Anim al> zoo;
                  return 0;
                  }






                  Comment

                  • Shane Beasley

                    #10
                    Re: typenames in self-referential templates

                    "Anthony Heading" <anthony@magix. com.sg> wrote in message news:<bkupth$ra 9$1@catv02.star cat.ne.jp>...
                    [color=blue][color=green]
                    > > Collection<Anim al> depends on Animal<Collecti on> (via inheritance),
                    > > but Animal<Collecti on> depends on Collection<Anim al> (via T::Name).
                    > > Can't do that.[/color]
                    >
                    > So I infer... but the rationale escapes me. Consider for contrast the code
                    > attached below, which _does_ run fine.
                    > It seems that function names are allowed to have such a circular dependency
                    > in templates, but not types.
                    > Why fundamentally is this OK, but the types are a no-can-do?[/color]

                    Actually, types are fine, too. What you did differently here was put
                    the use inside a function. Functions are exempt from this rule because
                    the compiler can pretend as though they are processed out of line,
                    whereas it can't generally do the same for declarations in the class.

                    For instance, this code compiles as well:

                    template <typename T> struct Animal {
                    void f () { typedef typename T::Name name; }
                    };

                    template <template <class> class T>
                    struct Collection : T< Collection<T> > {
                    typedef char *Name;
                    };

                    int main () { Collection<Anim al>().f(); }

                    The reason this works is because the compiler can reinterpret Animal
                    thus:

                    template <typename T> struct Animal { void f (); };

                    template <typename T>
                    inline void Animal<T>::f () {
                    typedef typename T::Name name;
                    }

                    Note that the mutual dependence between the class definitions is gone
                    -- the definition of Animal does not use T at all. As a result,
                    Animal< Collection<Anim al> > and Collection<Anim al> can be fully
                    processed, and then Animal::f() can work with the result.

                    Note, also, that this only applies to the bodies of the functions. For
                    instance, you can't do this:

                    template <typename T> struct Animal {
                    void f (typename T::Name *);
                    };

                    This reintroduces Animal's dependence on T.
                    [color=blue][color=green]
                    > > Perhaps there should be a third class with traits for Animal, such
                    > > that Collection< Animal<Traits> > would be used instead. More likely,
                    > > Animal should either have a hardcoded Name type, or it should be some
                    > > kind of global (or scoped) typedef -- are you really going to use
                    > > Animals with different types of Name in your program?[/color]
                    >
                    > I am. Obviously this is somewhat of a toy example, but one could imagine
                    > Asian animals whose
                    > Names are wchar_t. Clearly these would have need a Collection zoo of their
                    > own, since the
                    > type signature is different, but yes I could have both in the same program.[/color]

                    It's hard for me to critique a toy program in a way that applies to
                    the real program it models, so I'll leave that alone. :)
                    [color=blue]
                    > With a real program, I have templates mixed into a single class, and I just
                    > find it puzzling
                    > that the _functions_ can happily cross-call each other by passing in the
                    > aggregate class as
                    > a template param to its constituents, but the _types_ cannot be used that
                    > way.[/color]

                    Again, the classes' definitions cannot be mutually independent, though
                    their member functions' definitions can, even when they use dependent
                    types.

                    BTW, the tried-and-true way to resolve recursive dependence is to add
                    a level of abstraction:

                    template <typename T>
                    struct Animal { typedef typename T::Name name; };

                    struct CollectionTrait s { typedef const char *Name; };

                    template <template <class> class T>
                    struct Collection : Animal<Collecti onTraits> {
                    };

                    - Shane

                    Comment

                    Working...