0

I would like to know if it is possible to have a for loop in compile time with runtime or even compile time limit condition in c++11? I start with a silly try to find out what I need.

for (uint32_t i = 0; i < n; ++i)
  {
    templated_func<i>();
  }

consider I have a class with a private member variable n, and I want to call a template function with a different number that iterates from 0 to n (for the case of runtime limit condition) I've had studies on the "Template Metaprogramming" and "Constexpr If" (c++17) but I have not gotten any results, can anyone help me?

3 Answers3

2

You can't have a for loop, but you can call N lots of templated_func

namespace detail {
    template <template<uint32_t> class F, uint32_t... Is>
    void static_for_impl(std::integer_sequence<uint32_t, Is...>)
    {
        F<Is>{}()...;
    }
}

template <template<uint32_t> class F, uint32_t N>
void static_for()
{
    detail::static_for_impl<F>(std::make_integer_sequence<uint32_t, N>{}); 
}

template <uint32_t I>
struct templated_caller
{
    void operator()() { templated_func<I>(); }
}

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

Note that this is more general than what you asked for. You can simplify it to just

template <uint32_t... Is>
void call_templated_func(std::integer_sequence<uint32_t, Is...>)
{
    templated_func<Is>()...;
}

int main()
{
    call_templated_func(std::make_integer_sequence<uint32_t, N>{});
    return 0;
}

but that's lengthy to repeat multiple times, and you can't pass a function template as a template parameter.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Thank you @Caleth, I'm sure this solution works on c++14|17, but unfortunately, I'm limited to c++11. – Mohammad Ali Oct 17 '18 at 13:29
  • 2
    You can backport `std::integer_sequence` to C++11, but it's a bit of a faff. You can also adapt it to `call_templated_func<0, 1, 2, 3, 4, 5, 6, 7, 8, 9>()`, removing the `std::integer_sequence` parameter by specifying exactly the list – Caleth Oct 17 '18 at 13:33
  • This does not work for me. I get compiler error `expected ';' before token '...'` – user2762996 Apr 19 '23 at 20:53
1

As you said you only had C++11 then you will not have std::make_index_sequence and will have to provide it. Also, the fold expression in Caleth's answer is not available until C++17.

Providing your own implementation of index_sequence and a fold expression in c++11 can be done in the following way,

#include <iostream>

template <size_t... Is>
struct index_sequence{};

namespace detail {
    template <size_t I,size_t...Is>
    struct make_index_sequence_impl : make_index_sequence_impl<I-1,I-1,Is...> {};

    template <size_t...Is>
    struct make_index_sequence_impl<0,Is...>
    {
        using type = index_sequence<Is...>;
    };
}

template<size_t N>
using make_index_sequence = typename detail::make_index_sequence_impl<N>::type;


template<size_t I>
void templated_func()
{
    std::cout << "templated_func" << I << std::endl;
}

template <size_t... Is>
void call_templated_func(index_sequence< Is...>)
{
    using do_ = int[];
    do_ {0,(templated_func<Is>(),0)...,0};
}

int main()
{
    call_templated_func(make_index_sequence< 10>());
    return 0;
}

This is essentially the same as the answer by @Caleth , but with the missing bits provided and will compile on c++11.

demo

demo on c++11 compiler

rmawatson
  • 1,909
  • 12
  • 20
0

I would like to know if it is possible to have a for loop in compile time with runtime or even compile time limit condition in c++11

I don't know a reasonable way to have such loop with a runtime condition.

With a compile time condition... If you can use at least C++14, you can use a solution based on std::integer_sequence/std::make_integer_sequence (see Caleth answer) or maybe std::index_sequence/std::make_index_sequence (just a little more synthetic).

If you're limited with C++11, you can create a surrogate for std::index_sequence/std::make_index_sequence or you can create a recursive template struct with static function (unfortunately you can partially specialize a template function but you can partially specialize classes and structs).

I mean... something as follows

template <std::size_t I, std::size_t Top>
struct for_loop
 {
   static void func ()
    {
      templated_func<I>();
      for_loop<I+1u, Top>::func();
    }
 };

template <std::size_t I>
struct for_loop<I, I>
 { static void func () { } };

that you can call

constexpr auto n = 10u;

for_loop<0, n>::func();

if you want to call templated_func() with values from zero to n-1u.

Unfortunately this solution is recursive so you can have troubles with compilers recursion limits. That is... works only if n isn't high.

max66
  • 65,235
  • 10
  • 71
  • 111