Thread: Nested template

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    2

    Nested template

    I have been trying to reinforce my knowledge of templates lately, and was unable to get the following to compile.

    Code:
    #include <iostream>
    #include <list>
    
    using namespace std;
    
    template <class T>
    class A { };
    
    template <class T>
    class B {
            B() { std::list< A< T > >::const_iterator i; }
    };
    
    
    int main(void) {
            B<int> a();
            return 0;
    }
    My compiler is gcc 4.1.3, and the error is

    Code:
    test.cpp: In constructor ‘B<T>::B()’:
    test.cpp:11: error: expected `;' before ‘i’
    What am I doing wrong?

    Thanks!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I think you need to use typename, e.g.,
    Code:
    typename std::list< A< T > >::const_iterator i;
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by laserlight View Post
    I think you need to use typename, e.g.,
    Code:
    typename std::list< A< T > >::const_iterator i;
    I highlighted the critical bits. Whenever you refer to a type name through a scoping operator which is dependent on a template parameter, you must put the keyword "typename" in front.

    In other words, the presence of "T" (a template parameter) and a "::" to its right means that you need the "typename" keyword.

  4. #4
    Registered User
    Join Date
    Oct 2007
    Posts
    2

    Thanks

    This worked! Thanks for the great help and explanation!

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    I've only had to use that a couple times so far.
    I just don't really understand why WE are required to put the typename keyword there in the first place? Surely the compiler could figure this out for itself??

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I just don't really understand why WE are required to put the typename keyword there in the first place? Surely the compiler could figure this out for itself??
    From what I understand, the reason is that the compiler does not have enough information to determine if the name is a type name or a member name. Depending on the template argument, it could be interpreted one way or the other.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by laserlight View Post
    From what I understand, the reason is that the compiler does not have enough information to determine if the name is a type name or a member name. Depending on the template argument, it could be interpreted one way or the other.
    It seems to have plenty of information to me:
    Code:
    std::list< A< T > >::const_iterator i;
    1. Replace T with the type used with this template.
    2. Now it knows what types are stored in std::list.
    3. const_iterator is a typedef in std::list, so it knows what type to assign to i.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It might just be more of a silly requirement. All default values must be const (even though you could theoretically assign them), and all types within a namespace or class requires "typename" even though the compiler knows all the information.
    Might just be a thing in the standard that makes no sense!

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    1. Replace T with the type used with this template.
    From what I understand the problem is that at the time of parsing of the template, T is not known. The compiler cannot replace T with any type since the template has not been instantiated.

    I am not sure if this is a correct counterexample, but suppose there is a specialisation of std::list such that, for that particular A<T>, const_iterator is a member variable, not a type. Now, If T happens to be any other type, const_iterator would be a typename. But if T is of that type such that A<T> has this unusual specialisation, const_iterator would be a member variable.

    This would not happen in practice since we are dealing with a standard container (and my knowledge of templates and C++ in general is such that I am not sure if it is even legal/possible), so perhaps Stephen Dewhurst's example from C++ Common Knowledge Item #49 is clearer:

    Consider the following fragment:
    Code:
    template <typename T>
    void aFuncTemplate( T &arg ) {
        ...T::ElemT...
    When the compiler encounters the qualified name T::ElemT, what does it know? From the template parameter list it knows that T is a type name of some sort. It can also determine that T is a class name because we've employed the scope operator (: to access a nested name of T. But that's all the compiler knows, because there is no information available about the content of T. For instance, we could call aFuncTemplate with a PtrList, in which case T::ElemT would be a type name.

    Code:
    PtrList<State> states;
    //...
    aFuncTemplate( states ); // T::ElemT is PtrList<State>::ElemT
    But what if we were to instantiate aFuncTemplate with a different type?

    Code:
    struct X {
        enum Types { typeA, typeB, typeC } ElemT;
        //...
    };
    X anX;
    //...aFuncTemplate( anX ); // T::ElemT is X::ElemT
    In this case, T::ElemT is the name of a data member - a nontype name. What's a compiler to do? The standard tossed a coin, and in cases where it can't determine the type of a nested name, the compiler will assume the nested name is a nontype name.

    NB:
    For your reference, Dewhurst's PtrList example is:
    Code:
    template <typename T>
    class PtrList {
      public:
        //...
        typedef T *ElemT;
        void insert( ElemT );
        //...
    };
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I think the only point your argument fails at is that the compiler knows the type of T.
    Why? Because templates are only compiled if they invoked somewhere. And if they are, the compiler will know the type T or it will complain.
    At least this is my understanding of Microsoft's compilers.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I think the only point your argument fails at is that the compiler knows the type of T.
    Why? Because templates are only compiled if they invoked somewhere.
    I believe that is false. Templates are compiled whether or not they are instantiated, but if they are not instantiated, the compiler does not generate object code for the template instantiation. If not, templates with syntax errors should be ignored by the compiler since there is no reason to care about code that is never used.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Templates that are never used used are never compiled, or at least, as you mention, ignored.
    You can create a lot of compile errors in a template but never call it and the compiler will not complain.
    Therefore, the compiler can ignore template declarations when it does not know the type of T, and compile it only when it knows the type of T, and therefore the argument that the compiler does not know T fails.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    On Microsoft compilers, this is not the case. Templates that are never used used are never compiled.
    You can create a lot of compile errors in a template but never call it and the compiler will not complain.
    hmm... that is true, at least I can verify it with MSVC8.

    I think we need to call Prelude in on this. Dewhurst might be wrong, but considering that he has participated in the writing of C++ compilers on top of his experience, it seems unlikely.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I just had a look. Consider this:
    Code:
    template<typename T> void foo(T p)
    {
    	p = A;
    }
    Obviously this is faulty code, but it compiles find if I don't call the function.
    On the other hand, if I do call the function:
    Code:
    BOOL CKantanAnimeApp::InitInstance()
    {
    	char* p;
    	foo(p);
    }
    I get an error saying A in undeclared;
    The compiler will also parse the function header, though not the body. Leave out "void" for example, and it will complain.
    Tested on MSVC2005.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    The compiler will also parse the function header, though not the body.
    That makes sense, the compiler at least has to know what the template looks like in order to identify if it is or is not used. Like g++ 3.4.2, the Comeau online compiler also reports a compile error if the function template body has syntax errors, but this behaviour could be compiler specific as I have not found the relevant part of the standard concerning this.

    By the way, note that MSVC2005 is MSVC8.

    Reading the error message from the MinGW port of g++ 3.4.2 more closely, I see:
    test.cpp:12: error: dependent-name ` T::meta' is parsed as a non-type, but instantiation yields a type
    test.cpp:12: note: say `typename T::meta' if a type is meant
    It seems that the point really is about the parsing of the template. Comeau's C++ Template FAQ on What is the template typename keyword used for? reads:
    Additionally, there are various other different contexts from the above where the compiler needs to know whether it is dealing with a declaration or an expression. In the case of templates, similar parsing issues comes up. In particular, if T is a template parameter as it is in xyz above, then what does it mean for it to use say T::x? In other words, if the compiler does not know what T is until you instantiate it, how could it know what x is, since it is based upon T?
    This reiterates Dewhurst's claim that the typename keyword "allows the compiler to parse the template correctly".

    On the other hand, it seems from the g++ example that the compiler can parse the template "correctly", perhaps by first parsing the name as a nontype name, then parsing the template again but this time interpreting the name as a type name. If on the second try there is no syntax error because "instantiation yields a type", all is well. If so, my guess is that the real reasons for the standards committee decision to introduce typename are to make life a little easier for compiler writers, and to allow the compilation process to be a little faster, by forcing C++ programmers to make it clear that the type name is indeed a type name.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Template class nested in template class
    By yahn in forum C++ Programming
    Replies: 7
    Last Post: 04-18-2009, 11:40 AM
  2. Specialising a member function with a template template parameter
    By the4thamigo_uk in forum C++ Programming
    Replies: 10
    Last Post: 10-12-2007, 04:37 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. error: template with C linkage
    By michaels-r in forum C++ Programming
    Replies: 3
    Last Post: 05-17-2006, 08:11 AM
  5. oh me oh my hash maps up the wazoo
    By DarkDays in forum C++ Programming
    Replies: 5
    Last Post: 11-30-2001, 12:54 PM