是否有可能在编译时有一个 for 循环与运行时甚至在 c++11 中的编译时间限制条件?

Is that possible to have a for loop in compile time with runtime or even compile time limit condition in c++11?

我想知道在c++11中是否可以在运行时或什至编译时限制条件下在编译时有一个for循环? 我开始愚蠢地尝试找出我需要的东西。

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

考虑到我有一个带有私有成员变量 n 的 class,我想调用一个从 0 到 n 迭代的不同数字的模板函数(对于运行时限制条件的情况) 我已经对 "Template Metaprogramming" 和 "Constexpr If" (c++17) 进行了研究,但我没有得到任何结果,有人可以帮助我吗?

你不能有一个 for 循环,但是你可以调用 N 很多 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;
}

请注意,这比您要求的更笼统。您可以将其简化为

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;
}

但是重复多次会很冗长,而且您不能将 函数模板 作为模板参数传递。

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

我不知道一个合理的方法来让这样的循环具有运行时条件。

在编译时条件下...如果您至少可以使用 C++14,则可以使用基于 std::integer_sequence/std::make_integer_sequence 的解决方案(参见 Caleth 的回答)或者 std::index_sequence/std::make_index_sequence(只是稍微合成一点)。

如果你受限于 C++11,你可以为 std::index_sequence/std::make_index_sequence 创建一个代理,或者你可以创建一个带有静态函数的递归模板结构(不幸的是你可以部分特化一个模板函数,但你可以部分特化 类 和结构)。

我的意思是...如下

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 () { } };

你可以调用

constexpr auto n = 10u;

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

如果您想使用从零到 n-1u 的值调用 templated_func()

不幸的是,此解决方案是递归的,因此您可能会遇到编译器递归限制的问题。也就是说...只有在 n 不高时才有效。

正如您所说,您只有 C++11,那么您将没有 std::make_index_sequence,并且必须提供它。此外,Caleth 的答案中的折叠表达式在 C++17 之前不可用。

提供您自己的 index_sequence 实现和 c++11 中的折叠表达式可以通过以下方式完成,

#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;
}

这与@Caleth 的回答基本相同,但提供了缺失的位并将在 c++11 上编译。

demo

demo 在 c++11 编译器上