Passing a variable as a template argument

What is the value of i (that is not a constant) at compile time? There is no way to answer unless executing the loop. But executing is not "compiling" Since there is no answer, the compiler cannot do that.

Templates are not algorithm to be executed, but macros to be expanded to produce code. What you can do is rely on specialization to implement iteration by recursion, like here:

#include <iostream>

template<int i>
void modify()
{ std::cout << "modify<"<<i<<">"<< std::endl; }

template<int x, int to>
struct static_for
{
    void operator()() 
    {  modify<x>();  static_for<x+1,to>()(); }
};

template<int to>
struct static_for<to,to>
{
    void operator()() 
    {}
};


int main()
{
    static_for<0,10>()();
}

Note that, by doing this, you are, in fact, instantiating 10 functions named modify<0> ... modify<9>, called respectively by static_for<0,10>::operator() ... static_for<9,10>::operator().

The iteration ends because static_for<10,10> will be instantiated from the specialization that takes two identical values, that does nothing.


  1. "Why can't compiler evaluate i at compile time?"

    That would defeat the purpose of templates. Templates are there for the case where the source code looks the same for some set of cases, but the instructions the compiler needs to generate are different each time.

  2. "Is there any other to achieve the objective I am trying to achieve without changing the API interface?"

    Yes, look at Boost.MPL.

    However I suspect the right answer here is that you want to change the API. It depends on the internals of the modify function. I know you have it's source, because templates must be defined in headers. So have a look why it needs to know i at compile time and if it does not, it would be best to replace (or complement if you need to maintain backward compatibility) it with normal function with parameter.


Since you asked for an answer using Boost.MPL:

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>

#include <iostream>

template <int N>
void modify()
{
    std::cout << N << '\n';
}

// You need to wrap your function template in a non-template functor
struct modify_t
{
    template <typename N>
    void operator()(N)
    {
        modify<N::value>();
    }
};

int main()
{
    namespace mpl = boost::mpl;

    mpl::for_each< mpl::range_c<int,0,10> >( modify_t() ); // prints 0 to 9
}

Tags:

C++

Templates