Name resolution issue

Discussion in 'C++' started by Ken Camann, Apr 2, 2007.

  1. Ken Camann

    Ken Camann Guest

    I think I understand why the following is happening (it compiles in
    both MSVC++ and gcc) I just wanted to be sure I understand the
    language issues at work here. I define this very simple class in
    classa.h:

    template <typename T> class B; //forward declaration of B

    template <typename T>
    class A
    {
    public:
    A() : x(0);
    T getX() const {return x;}
    void setX(T _x) {x = _x;}

    changeY(B<T>& bref)
    {
    bref.setY(bref.getX() + 1);
    }

    private:
    T x;
    };

    so I have a class "A" which stores a variable x. Similarly, I have a
    symmetric class B which is almost the same but stores a variable y,
    has a getY, setY, and changeX(A<T>& aref), forward declares A, etc.,
    and is defined in classb.h

    Now I can use these in the expected way, by #including classa and
    classb in main.cpp, and increasing both x and y by 1, but indirectly
    (calling changeY on A with the B instance and changeX on B with the A
    instance).

    My initial thought was that this would not work. This is what I
    thought would happen:

    1. Compiler sees #include "classa.h", includes it
    2. Compiler sees "template <typename T> class B" forward declaration
    3. Compiler parses declaration of class A. It's ok that it finds the
    symbol B<T>& because of the forward declaration
    4. Compiler parses definition of member function A<T>::changeY. This
    references the names B<T>::getY and B<T>::setY. Compiler complains
    because it while it recognizes reference types involving B<T> (like
    B<T>* or B<T>&) because of the forward declaration, member names in
    B<T> are still undefined symbols because it hasn't read the class B
    declaration yet (to be included in the future, by the inclusion of
    classb.h)

    And yet the code worked. I have a guess as to why this is, I was
    hoping someone could tell me if this is right, and if this is standard
    C++ behavior:

    This is OK because types are checked, but definitions are not
    generated until template instantiation takes place. By the time that
    happens (below both #include directives), both the declarations and
    definitions of A and B have been encountered in the translation unit
    main.cpp, so everything will work. This means you don't need to worry
    about anything as long as you include all the h files at the top of
    a .cpp translation unit; by the time your actual .cpp code is reached,
    everything can see the entire definition/declaration of everything
    else.

    It also means that specializations of A (e.g., A<int>) cannot
    reference specializations of B like B<int>, since this looks like an
    instantiated type to the compiler. Instead, you must work with a
    member template version of changeX, templatized with T, and accepting
    generic type B<T>&. The same is true for the definition of changeY in
    B<int>. At instantiation time, the correct thing will still happen,
    since you will actually pass the method a B<int>&, and the B<int>
    specialization has now been seen by the compiler during the #include
    phase.

    Is this basically correct? I tried to look this up myself in "The C++
    Programming Language" but I couldn't find it (I wasn't sure what the
    name of this little detail is called in C++ parlance).

    Thanks,
    Ken
     
    Ken Camann, Apr 2, 2007
    #1
    1. Advertising

  2. On 3 Apr, 00:12, "Ken Camann" <> wrote:
    > I think I understand why the following is happening (it compiles in
    > both MSVC++ and gcc) I just wanted to be sure I understand the
    > language issues at work here. I define this very simple class in
    > classa.h:
    >
    > template <typename T> class B; //forward declaration of B
    >
    > template <typename T>
    > class A
    > {
    > public:
    > A() : x(0);
    > T getX() const {return x;}
    > void setX(T _x) {x = _x;}
    >
    > changeY(B<T>& bref)
    > {
    > bref.setY(bref.getX() + 1);
    > }
    >
    > private:
    > T x;
    >
    > };
    >
    > so I have a class "A" which stores a variable x. Similarly, I have a
    > symmetric class B which is almost the same but stores a variable y,
    > has a getY, setY, and changeX(A<T>& aref), forward declares A, etc.,
    > and is defined in classb.h
    >
    > Now I can use these in the expected way, by #including classa and
    > classb in main.cpp, and increasing both x and y by 1, but indirectly
    > (calling changeY on A with the B instance and changeX on B with the A
    > instance).
    >
    > My initial thought was that this would not work. This is what I
    > thought would happen:
    >
    > 1. Compiler sees #include "classa.h", includes it
    > 2. Compiler sees "template <typename T> class B" forward declaration
    > 3. Compiler parses declaration of class A. It's ok that it finds the
    > symbol B<T>& because of the forward declaration
    > 4. Compiler parses definition of member function A<T>::changeY. This
    > references the names B<T>::getY and B<T>::setY. Compiler complains
    > because it while it recognizes reference types involving B<T> (like
    > B<T>* or B<T>&) because of the forward declaration, member names in
    > B<T> are still undefined symbols because it hasn't read the class B
    > declaration yet (to be included in the future, by the inclusion of
    > classb.h)
    >
    > And yet the code worked. I have a guess as to why this is, I was
    > hoping someone could tell me if this is right, and if this is standard
    > C++ behavior:
    >
    > This is OK because types are checked, but definitions are not
    > generated until template instantiation takes place. By the time that
    > happens (below both #include directives), both the declarations and
    > definitions of A and B have been encountered in the translation unit
    > main.cpp, so everything will work. This means you don't need to worry
    > about anything as long as you include all the h files at the top of
    > a .cpp translation unit; by the time your actual .cpp code is reached,
    > everything can see the entire definition/declaration of everything
    > else.
    >
    > It also means that specializations of A (e.g., A<int>) cannot
    > reference specializations of B like B<int>, since this looks like an
    > instantiated type to the compiler. Instead, you must work with a
    > member template version of changeX, templatized with T, and accepting
    > generic type B<T>&. The same is true for the definition of changeY in
    > B<int>. At instantiation time, the correct thing will still happen,
    > since you will actually pass the method a B<int>&, and the B<int>
    > specialization has now been seen by the compiler during the #include
    > phase.
    >
    > Is this basically correct? I tried to look this up myself in "The C++
    > Programming Language" but I couldn't find it (I wasn't sure what the
    > name of this little detail is called in C++ parlance).


    The sad truth is that many compilers don't bother with templates until
    they are instantiated, which means that you can write lots of classes
    and everything compiles fine until you try to instantiate one of them.
    Or you can successfully instantiate a class and use it but when you
    later try to use one of it's methods for the first time it all breaks
    down.

    I didn't read your code carefully enough to see if it will work or not
    but in my experience you'll never know until you try.

    --
    Erik Wikström
     
    =?iso-8859-1?q?Erik_Wikstr=F6m?=, Apr 3, 2007
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andrew FPGA
    Replies:
    0
    Views:
    1,001
    Andrew FPGA
    Sep 26, 2005
  2. Shadow Lynx
    Replies:
    1
    Views:
    3,033
    Christopher Reed
    Feb 4, 2006
  3. Replies:
    4
    Views:
    326
    stone
    Apr 6, 2007
  4. maverick83

    screen resolution css issue

    maverick83, Apr 14, 2009, in forum: HTML and CSS
    Replies:
    0
    Views:
    639
    maverick83
    Apr 14, 2009
  5. rocky
    Replies:
    2
    Views:
    332
    rocky
    Jul 7, 2009
Loading...

Share This Page