Click here to Skip to main content
15,917,709 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello all,
just as everybody would expect following snippet does not compile

C++
namespace NonTemplate{

  struct Unknown;

  struct AnyStruct{
    Unknown *p;
    AnyStruct(Unknown* p): p(p){}
    void doStuff(){ p->doStuff(); } // <-- error: use of undefined type 'NonTemplate::Unknown'
  };

  struct Unknown{
    void doStuff(){}
  };

}


but why this does?
C++
namespace Template {

  template<typename T> struct Unknown;

  template<typename T> struct AnyStruct {
    Unknown<T> *p;
    AnyStruct(Unknown<T>* p) : p(p) {}
    void doStuff() { p->doStuff(); } // <-- OK
  };

  template<typename T> struct Unknown {
    void doStuff() {}
  };
}


P.S. I tried both with VC6 and VC2013.
Posted

1 solution

The difference is caused by the fact that for templates the compiler generates the code the moment it is needed!

The compiler doesn't read the entire code before trying to interpret a statement: at this point it will only know the types and definitions it has seen before. Therefore, in your first example, it will not know that the staruct Unknown has a function called doStuff()

In the second case however, the compiler sees a templated class and tries to instantiate that template. As it is scoped within the namespace Template, it will scan the entire namescape for the definition of this template.

The reason the compiler works differently on templates is because it must! Templated code is instantiated only when the compiler finds an actual instantiation, and therefore there is no safe way to ensure all relevant template definitions are parsed in a specific order. Therefore the compiler must be able to search the entire code for template definitions, even in code it hasn't parsed for compilation yet.
 
Share this answer
 
Comments
ucarcamagnu 12-Jun-15 8:06am    
Thank you, I suspected exactly what you said because I heard about compiler generating "concrete" code out of templates, but need a confirmation.
I never thought about this being a great way to decouple classes, am I wrong?

struct Unknown; // no need to be template

template<typename t=""> struct S{ // no need to #include anything related to Unknown
void useUnknown(Unknown& u){
u.doStuff(); // just betting Unknown::doStuff exists, otherwise compile error
}
};
Stefan_Lang 12-Jun-15 8:26am    
Actually I never thought of it as a way to decouple classes. Also, I don't see the need:

In your example, the correct solution would be to simply move the implementation to the implementation file (.cpp file). Or, more to the point, move all function implementations to the implementation file! This really is necessary, because if you include that header in more than one implementation file, the compiler would generate multiple copies of the function implementations, and the linker wouldn't know what to do about them (i. e. , issue an error)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900