8

Possible Duplicate:
Incomplete class usage in template

I have a question that has been puzzling me for a couple of hours.

Initially I thought that the type would have to be complete at the point of instantiation, but all compilers I have tried accept the type to still be incomplete at that point, as long as it is defined anywhere in the translation unit.

To illustrate it, the question is about the correctness of this simple program:

template <typename T>
int size() {
   return sizeof(T);   // T is required to be complete in this expression
}
class test;            // test is declared, but incomplete

int main() {
   size<test>();
}
// [1] point of instantiation of size<test>()

class test {};         // Definition of test, now it is complete

According to §14.6.4.1/1 the point of instantiation of size<test> is the line marked as [1], and at that point the type test is still incomplete. If we had tried to perform the sizeof(test) operation there, the compiler would have failed telling us that the type is incomplete. And yet calling a template inside which the type to perform that same exact operation compiles in g++, clang++, comeau and Visual Studio 2010.

Is the previous code really correct? Where in the standard does it support that the type used as argument to the template is considered complete if it is complete anywhere in the same translation unit? Or when must it be complete?

Community
  • 1
  • 1
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Very similar question: http://stackoverflow.com/questions/7210286 – aschepler Oct 26 '11 at 00:32
  • @aschepler: I believe that they are exactly the same, the only difference so I have voted to close. I am not deleting it (yet) to *bump* your question up and see if anyone comes up with an answer (the only answer to your question is a bit off). Thanks for pointing the duplicate. – David Rodríguez - dribeas Oct 26 '11 at 00:38
  • @aschepler: definitely a duplicate, however this question seems to be getting more attention (life is unfair). I'd really like our standardistas to jump in here. – Matthieu M. Oct 26 '11 at 08:33

1 Answers1

1

The template is not compiled until after it is expanded at the end (test is complete by that time).

MartyTPS
  • 530
  • 2
  • 5
  • I agree that this is consistent with the behavior of those compilers, but I am trying to figure out whether this is consistent with the rules in the standard or not. +1 anyway. – David Rodríguez - dribeas Oct 26 '11 at 08:24
  • That would be the behavior of MSVC, but from a Standard point of view I would have expected the generation to take place at the first point of instantiation. – Matthieu M. Oct 26 '11 at 08:33
  • @MatthieuM.: That behavior is consistent in all compilers I have tried, so it is not just MSVC. Alf Steinbach in the chat pointed to the phases of translation and in particular to 2.2/8 that indicates that template instantiation is performed in a later phase that the translation of non-templated code. This only indicates that *in time* the instantiation is performed *after* all the TU has been processed, yet it does not mean that *in space* the type does not need to be complete before the *point of instantiation*. I have added that as answer to the duplicate. – David Rodríguez - dribeas Oct 26 '11 at 10:46
  • @DavidRodríguez-dribeas: Yes, I understand the time/context difference. It's just that it's a known bug of MSVC that the templated code is fully instantiated at the end of the TU, and there is no "remembrance" of the context (even later declaration of non-dependent functions are taken into account for example)... but let's bring the discussion to the other question :p – Matthieu M. Oct 26 '11 at 11:56
  • Ok, you made me curious enough to dig into the gcc source. I have a feeling that expanded template include files are generated in memory for templates on a first pass. oh, look, a template.. pass this whole tu to the generate a virtual template header function before continuing to compile the rest of this tu. In effect one path through the TU only cares about assembly a complete template header. I'll let you know what I see. – MartyTPS Oct 26 '11 at 15:50
  • I have been ripping apart pt.c in gcc (which parses templates). Template parameters are not treated as types at all until you are calling a method that uses the parameter. The calls are not linked up until all the trees for all the types have been built. You can, in fact, even use a template with an incomplete type parameter as long as you never call a method that uses that parameter (add a method to the template that does not use the parameter and comment out the complete declaration of the template parameter completely) – MartyTPS Oct 26 '11 at 19:18
  • this is completely "legal" too template class test { public: int size() { return sizeof(T);} int nothing() {return 0;} }; class forward; int _tmain(int argc, _TCHAR* argv[]) { test test1; //return test1.size(); return test1.nothing(); } – MartyTPS Oct 26 '11 at 19:22
  • The curiosuly recurring template pattern relies on the fact that you can use incomplete types in the template body so long as the types are defined "later" (in the CRTP, a type is defined to derive from a template class that takes that type as a parameter). I simply don't know how much later is still legal. – Max Lybbert Oct 31 '11 at 17:35