wikipedia (here) gives a compile time unrolling of for loop.......
i was wondering can we use a similar for loop with template statements inside...
for example...
is the following loop valid
template<int max_subdomain>
void Device<max_sudomain>::createSubDomains()
{
for(int i=0; i< max_subdomain; ++i)
{
SubDomain<i> tmp(member);
...
// some operations on tmp
...
}
}
SubDomain is a class which takes in the a template parameter int and here has been constructed with an argument that is a member of the Device class.
Thanks for the answer guys...
now that you know what i want...
is there anyway i achieve what i want to??
i finally got what i wanted..............
instead of using the for loop directly...
one can instead use the Boost::MPL for_each construct. I haven't yet implemented it but I am guessing that this provides a way to do what i wanted.....
I took the answer from another stack overflow question here... However the comment to the same question decries its use because it would be very slow (for large for loops of course)... however.. for loops which are not large i don't think there should be any bloating... i'll try the code and let you know the results....
the use is illustrated well in the example
Re-Edit:
My previous answer was correct. I have tried your code, it's giving compiler error. You cannot declare objects like that, as i
cannot remain a compile time constant (as you are intending to do i++
). template
parameter must always be compile time constants. Here is the demo.
Also note that, loop unrolling is done for normal loops also, as part of optimization by compilers. It's not limited to template
s.
There's a stadard solution for this. Convert iteration into recursion.
template<int i>
void Device::createSubDomains()
{
SubDomain<i> tmp(member);
// some operations on tmp
createSubDomains<i-1>();
}
template<>
void Device<-1>::createSubDomains()
{
// End of recursion.
}
Note: you can't use a runtime if(i!=0) createSubDomains<i-1>();
.
2017 Note: you can now use a compile-time if constexpr(i!=0) createSubDomains<i-1>();
Even though you already accepted @iammilind 's answer, let me propose another one, because his reasoning for why i
is not compile-time-constant is was not correct.
Suppose you have
template<unsigned int MAX> struct SubDomain {...};
...
and you want to declare an instance of it ...
SubDomain<i> tmp(member);
then i
must be a commonly so-called compile-time-constant. What is that?
Pedantry
The standard assigns the term nontype template argument
to template arguments that are not types (D'Oh).
14.3.2 Template non-type arguments [temp.arg.nontype]
A template-argument for a non-type, non-template template-parameter shall be one of:
— an integral constant-expression of integral or enumeration type; or
— ... [more follow, but are not relevant]
Right the first point contains a reference for further research: an integral constant-expression
. This leads us to
5.19 Constant expressions [expr.const]
In several places, C + + requires expressions that evaluate to an integral or enumeration constant: as array
bounds (8.3.4, 5.3.4), as case expressions (6.4.2), as bit-field lengths (9.6), as enumerator initializers (7.2),
as static member initializers (9.4.2), and as integral or enumeration non-type template arguments (14.3).
Then, the key is:
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static
data members of integral or enumeration types initialized with constant expressions (8.5), non-type template
parameters of integral or enumeration types, and sizeof expressions.
Pedantry application
If we look back at your loop:
for (int i=...
...
SubDomain<i>
then we can now observe that i
is not allowed there. Why? Because i
is NOT a const variable
.
The observing reader might now think you can circumvent this:
for (int i=...
...
const int I = i;
SubDomain<I>
But is this really allowed? Negative, I = i
is not an integral constant-expression, because i
is not. It helps to realise that the rule for integral constant-expressions is applied recursively.
E.g., the following is valid code:
template <int> void foo() {}
int main () {
const int ccI = 0;
const int ccJ = ccI*2;
const int ccK = ccJ/4;
foo<ccK>();
}
But if make just one part of the chain non-const, then ccK
is not considered integral constant anymore:
template <int> void foo() {}
int main () {
int ccI = 0;
const int ccJ = ccI*2; // not compile time constant
const int ccK = ccJ/4; // same
foo<ccK>(); // error
}
Summary
So, in human readable form, template arguments that are not types, but (integer) values, must be compile-time-constant:
- the initializer of a compile-time-constant must only involve other compile-time-constants
- a literal value is a compile-time-constant
- an enum value is a compile-time-constant
- function-calls don't give compile-time-constants (for some advanced reasons)