Prev: Simplest MetaLoop
Next: Standard library pop()
From: Bart van Ingen Schenau on 2 Nov 2009 04:05 PGK wrote: > Thanks Daniel, yes that does help: > >> Yes. Note that template instantiation is a process that happens >> during compile-time, but your code below uses a run-time test. >> Without a specialization that stops the recursion the compiler >> is supposed to instantiate every specialization that requires >> instantiation. Some examples of preconditions for instantiation >> are object creation or usage of members. The latter happens >> below. > > The only question I am left with is, why exactly does the compiler > stop there? By that I don't mean that it should, but rather, is it > part of > the C++ standard; or a design choice of my compiler? The limit on the template instantiation limit is a design choice by the compiler, and I believe there are options for GCC to change that maximum. The reason they have a maximum at all, is because people prefer to get a nice message that something is wrong with their code rather than a computer that crawls to a halt or a crashing compiler. > For example, > it seems like in this example the compiler could determine that, as > "i" is > a constant, and the only instantiation is with a "1" ( i.e. > Loop2<1>::foo() ), > only two instances need to be built. But, when the compiler is instantiating the templates, it must assume that every line in the templated code will be present in the final executable (because there are some compilers around that don't eliminate unreachable code, and you don't want the validity of a construct to depend on the optimisations that a compiler might or might not perform), so when instantiating Loop2<1>::foo(), the compiler sees it needs Loop2<0>::foo(), that in turn needs Loop2<-1>::foo(), that in turn needs .... (ad nauseam). > > Best regards, > Graham > Bart v Ingen Schenau -- a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq c.l.c FAQ: http://c-faq.com/ c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/ [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 2 Nov 2009 04:26
On 2 Nov., 16:30, PGK <graham.k...(a)gmail.com> wrote: > Thanks Daniel, yes that does help: > > > Yes. Note that template instantiation is a process that happens > > during compile-time, but your code below uses a run-time test. > > Without a specialization that stops the recursion the compiler > > is supposed to instantiate every specialization that requires > > instantiation. Some examples of preconditions for instantiation > > are object creation or usage of members. The latter happens > > below. > > The only question I am left with is, why exactly does the compiler > stop there? By that I don't mean that it should, but rather, is it > part of > the C++ standard; or a design choice of my compiler? For example, > it seems like in this example the compiler could determine that, as > "i" is > a constant, and the only instantiation is with a "1" ( i.e. > Loop2<1>::foo() ), > only two instances need to be built. Your compiler behaves according to the rules of the standard. Regarding the situation in your example it is completely irrelevant, whether there is an if branch or not, the compiler is supposed to instantiate the complete code in the foo function, if this is instantiated. There is no concept of partial instantiation of the implementation of a function in C++. > template<int i> > struct Loop2 { > static inline void foo() { > if (i>0) { > std::cout << "i is " << i << ", "; > Loop2<i-1>::foo(); > } > else { > std::cout << "i is " << i << std::endl; > } > } > }; > > int main(int argc, char *argv[]) > { > Loop2<1>::foo(); > return 0; > } The compiler is supposed to do the following: Your main function /uses/ Loop2<1> in a way that requires instantiation (call of a member function). This usages requires a complete definition of Loop2<1>::foo(). Now the compiler starts instantiating the *implementation* of Loop2<1>::foo(). During that process it recognizes that this implementation /uses/ Loop2<0>::foo() (again: Call of a member function) etc. ad infinitum, because each such foo again /uses/ one not yet instantiated specialization of Loop2. There are situations where a template shall not be instantiated, e.g. consider a (quite useless) variant of your example: template<int i> struct Loop2 { static void foo() { typedef Loop2<i-1> type; if (i>0) { std::cout << "i is " << i << std::endl; } } }; I present it just to point out the difference between /using/ an entity in C++ and not using one. The typedef above does not require instantiation and a compiler is not allowed to try to perform instantiation in this specific situation. Your reasoning regarding that i is a constant does not help here, because in C++ there is no concept of a compile-time sub-block. You can realize the same effect with a bit more work by using a compile-time-if. #include <iostream> template<bool value, class TrueT, class FalseT> struct if_c { typedef FalseT type; }; template<class TrueT, class FalseT> struct if_c<true, TrueT, FalseT> { typedef TrueT type; }; template<int i> struct Stop { static void foo(){ std::cout << "i is " << i << std::endl; } }; template<int i> struct Loop2 { static void foo() { std::cout << "i is " << i << ", "; if_c<(i>0), Loop2<i-1>, Stop<i> >::type::foo(); } }; int main() { Loop2<1>::foo(); } HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |