Re: Simplester MetaLoop
On 2 Nov., 16:30, PGK <graham.k...@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! ]