遍历具有 int 类型的模板化 C++ 函数
Looping over a templated C++ function with int type
是否有像这样的解决方案来循环使用模板化 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;
};
你说过“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
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> );
}
你的主图现在看起来像
do_foreach_index_upto<N>([](auto I){ LoopFunc{}.body<I>(); });
但是LoopFunc
class确实不需要。您可以直接调用 some_func<I>()
。
我们在这里所做的是制作无状态编译时值,表示最大为 10 的整数。我们将它们填充到一个元组中,使用 std apply 解包,然后使用 do_foreach_arg
.[=17= 解包。 ]
我们可能会在这里跳过元组“步骤”,但更高级的使用会发现它很有用。
是否有像这样的解决方案来循环使用模板化 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;
};
你说过“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
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> );
}
你的主图现在看起来像
do_foreach_index_upto<N>([](auto I){ LoopFunc{}.body<I>(); });
但是LoopFunc
class确实不需要。您可以直接调用 some_func<I>()
。
我们在这里所做的是制作无状态编译时值,表示最大为 10 的整数。我们将它们填充到一个元组中,使用 std apply 解包,然后使用 do_foreach_arg
.[=17= 解包。 ]
我们可能会在这里跳过元组“步骤”,但更高级的使用会发现它很有用。