【问题标题】:Looping over a templated C++ function with int type循环使用 int 类型的模板化 C++ 函数
【发布时间】:2026-02-15 07:10:01
【问题描述】:

是否有这样的解决方案来循环使用模板化 int 参数的函数,而无需在任何时候使用 forIdx 使用新函数创建具有 body() 函数的新结构? C++20 中的模板化 lambda 看起来很有希望,但似乎不可能指定不会自动推导的模板参数。

struct LoopFunc {
    template <int i>
    void body() {
        std::cout << i;
    };
};

template<int i>
struct forIdx {
    template<typename T>
    static void loop(T&& func) {
        func.body<i>();
        forIdx<i - 1>::loop(func);
    }
};

template<>
struct forIdx<-1> {
    template<typename T>
    static void loop(T&& func) {};
};

int main() {
    forIdx<10>::template loop(LoopFunc{});
}

该函数用于创建元组元素的笛卡尔积。 DirectProduct 包含所有具有静态 generateAllElements() 函数的元素。

    struct CrossProduct {
        std::tuple<MockElement...> vals;
        std::set<DirectProduct> result;
        template <int num>
        void body() {
            if (result.empty()) {
                for (const auto& e2 : std::get<num>(vals).generateAllElements()) {
                    DirectProduct tmp;
                    std::get<num>(tmp.vals) = e2;
                    result.insert(tmp);
                }
            }
            else for (const DirectProduct& e1 : result)
                for (const auto& e2 : std::get<num>(vals).generateAllElements()) {
                    DirectProduct tmp = e1;
                    std::get<num>(tmp.vals) = e2;
                    result.insert(tmp);
                }
        };
    };

DirectProduct 在自己的generateAllElements() 函数中使用CrossProduct

    std::set<DirectProduct> generateAllElements() const {
        CrossProduct crossProduct{ };
        forIdx<std::tuple_size<std::tuple<MockElement...>>::value - 1>::template loop(crossProduct);
        return crossProduct.result;
    };

【问题讨论】:

  • 不要constexprconsteval 功能适合您的需求?
  • 实际使用forIdx需要函数为void,但它也确实需要调用它的函数中的数据,所以我其实不知道自己尝试的能不能做到没有结构或某种 lambda。
  • 我提供的解决方案似乎可以回答您的问题,但您的评论表明可能存在一些从显示的代码中看不到的额外限制。如果是这样,请编辑问题以澄清这一点。
  • 这是创建元组元素的笛卡尔积,我能够简单地遍历元组的元素,但是当可能存在重复类型时访问和修改元组的特定索引是问题
  • 那么这是一个 XY 问题,即您要解决的问题与您提出的问题不同。正如我所说,请编辑问题以明确您想要实现的目标;您根本没有提到任何关于叉积、元组或不同类型的内容。

标签: c++ templates variadic-templates template-meta-programming c++20


【解决方案1】:

“C++20 中的模板化 lambda”你说过吗?

你的意思是这样的吗?

#include <iostream>
#include <type_traits>

template <std::size_t I>
void loop_func()
 { std::cout << I << ' '; };

int main ()
 {
    []<std::size_t ... Is>(std::index_sequence<Is...>)
    { (loop_func<sizeof...(Is)-Is-1u>(), ...); }
    (std::make_index_sequence<11u>{});
 }

打印出来的

10 9 8 7 6 5 4 3 2 1 0

【讨论】:

  • 这似乎正是我想要的,谢谢
  • @JoyMcGibbon 最好的说法就是实际接受答案。
  • 谢谢,新手
【解决方案2】:
template<auto x>
using value_t=std::integral_constant<std::decay_t<decltype(x)>,x>;
template<auto x>
constexpr value_t<x> value={};
template<std::size_t...Is>
using indexes_t=std::tuple<value_t<Is>...>;
template<std::size_t>
constexpr indexes_t<Is...> indexes={};

一些编译时间值。

template<std::size_t N>
constexpr auto indexes_upto=[]<std::size_t...Is>(std::index_sequence<Is...>){ return indexes<Is...>; }( std::make_index_sequence<N>{} );

现在我们差不多完成了。

void do_foreach_arg(auto f){
  return [&](auto&&...args){
    ((void)(f(std::forward<decltype(args)>(args))),...);
  };
}
template<std::size_t N>
auto do_foreach_index_upto( auto f ){
  std::apply( do_foreach_arg(std::move(f)), indexes_upto<N> );
}

你的 main 现在看起来像

do_foreach_index_upto<N>([](auto I){ LoopFunc{}.body<I>(); });

LoopFunc 类确实不需要。您可以直接拨打some_func&lt;I&gt;()

我们在这里所做的是,我们将无状态的编译时间值表示为最大 10 的整数。我们将它们填充到一个元组中,使用 std apply 解包,然后使用 do_foreach_arg 解包。

我们可能可以跳过这里的元组“步骤”,但更高级的使用会发现它很有用。

【讨论】: