C++ 提取类的模板参数并对其进行迭代的最简洁的方法是什么?
在下面的小程序中,我展示了当前用于提取类的模板参数并通过递归帮助函数对其进行迭代的解决方案 我想知道是否有一种更简洁的方法可以做到这一点,正如我在下面注释中的伪代码中所解释的那样C++ 提取类的模板参数并对其进行迭代的最简洁的方法是什么?,c++,templates,c++11,c++14,variadic-templates,C++,Templates,C++11,C++14,Variadic Templates,在下面的小程序中,我展示了当前用于提取类的模板参数并通过递归帮助函数对其进行迭代的解决方案 我想知道是否有一种更简洁的方法可以做到这一点,正如我在下面注释中的伪代码中所解释的那样 template <int...Is> struct Pack {}; template <int I> struct B { static void foo() { std::cout << I << "\n"; } }; // recursive help
template <int...Is> struct Pack {};
template <int I> struct B
{
static void foo() { std::cout << I << "\n"; }
};
// recursive helper function, also used to extract the parameter pack arguments
template <int I, int...Is>
void foo_helper( Pack<I, Is...>&& )
{
B<I>::foo();
foo_helper( Pack<Is...>{} );
}
// terminate recursion
void foo_helper( Pack<>&& ) {}
struct A
{
typedef Pack<1,3,5> ints;
static void foo()
{
// this is what I do
foo_helper(ints{});
// this is what I would like to do, ideally in one single line
// 1) extract the template arguments pack from ints, without creating an helper function for that
// 2) iterate on the template arguments of the pack without a recursive helper
// In pseudocode, something like:
// (B<IterateOver<ArgumentsOf<ints>>>::foo());
}
};
int main()
{
A::foo();
}
模板结构包{};
模板结构B
{
静态void foo(){std::cout您可以为每个
函数添加一个foo\u到Pack
:
template <int...Is> struct Pack {
template <template <int> class T>
static void foo_for_each () {
std::initializer_list<int> { (T<Is>::foo(),0)... } ;
}
};
然后你可以这样打电话:
auto call_foo = [](auto tag) { type_t<decltype(tag)>::foo(); };
ints::for_each<B>(call_foo);
auto-call_-foo=[](自动标记){type_-t::foo();};
ints::for_each(调用_foo);
如果您想在运行时迭代中使用变量包,可以将std::array
附加到结构包上,如下所示:
template <int...Is> struct Pack {
std::array<int, sizeof...(Is)> arr = {{Is...}};
};
模板结构包{
数组arr={{Is…}};
};
然后以如下方式迭代:
static void foo() {
for(auto && i : ints{}.arr) std::cout << i << " ";
}
静态void foo(){
对于(auto&&i:ints{}.arr)std::cout来说,您在这里编写的内容非常奇怪,您在哪里找到了这个实现
僵硬
您需要一个助手函数,这只是一个事实,您可能需要解决它
不知怎么的,但我不明白这有什么意义
目前唯一的解决方案是使用Clang3.6,他们已经实现了
新语法允许您编写类似这样的内容
//我很确定,这就是语法,它被称为折叠表达式
//您可以在此处阅读更多信息:
//
或
还有其他一些使用可变模板的方法,就像这家伙描述的,
它的内容太多了,我无法把它放在这里,所以我将链接:
迭代模板的参数有点困难,因为必须使用
一些真正的编译器魔术和索引_序列
我有一个例子就在这里的某个地方,因为我一直在胡闹
我最近一直在抱怨
template<typename InputTuple, std::size_t ... N>
void tupleIteratorImpl(InputTuple& input, std::index_sequence<N...>)
{
// DO WHATEVER YOU WANT HERE, but the structure is
FUNCTION(/* pass all of the template parameters as arguments */, std::get<N>(input)...);
// and FUNCTION has to have the structure of the examples from point 1.
// but with this, you can already do pretty much anything you imagine
// even at compile time
}
template<typename InputTuple, typename Indices = std::make_index_sequence<std::tuple_size<InputTuple>::value>>
void tupleIterator(InputTuple& input)
{
tupleIteratorImpl(input, Indices());
}
模板
无效元组畸胎学MPL(输入元组和输入,标准::索引\u序列)
{
//你想做什么就做什么,但结构是
函数(/*将所有模板参数作为参数传递*/,std::get(input)…);
//函数必须具有第1点示例的结构。
//但是有了这个,你已经可以做你想象的任何事情了
//即使在编译时
}
模板
无效元组计算器(输入元组和输入)
{
tupleIteratorImpl(输入,索引());
}
c++17中已经包含了一个函数,名为apply,以下是文档:
甚至还有一些示例代码
希望这能回答您的一些问题。如果您想进行元编程,请开始使用类型。如果您想使用非类型模板参数,请尽快将其移动到类型
下面,我首先将Pack
转换为类型
。这是一个与您的整数包明显对应的类型列表
然后,我介绍一个标记类型模板。这是一个“携带”另一个类型的类型,但它本身是无状态的。作为奖励,您可以从模板实例的值中提取该类型
第三,我编写了一个“for each type”函数,它接受一个lambda和一组类型,并继续为每个类型调用lambda一次,传递一个标记类型
在lambda的主体中,我们可以通过对标记变量(或helper宏)使用decltype
来提取传递的类型
我们将它们链接在一起,并从传递的标记类型中提取原始包中的整数
结果是,您可以将以下内容插入到代码中:
for_each_type( [&](auto tag){
constexpr int i = TAG_TYPE(tag){};
// use i
}, ints_as_types_t<ints>{} );
它允许您在类型集合上进行迭代
for_each_type( [&](auto tag){
constexpr int i = TAG_TYPE(tag){};
// use i
}, ints_as_types_t<ints>{} );
每种类型([&](自动标记)的{
constexpr int i=TAG_TYPE(TAG){};
//使用我
},ints_as_类型{});
为列表中的每种类型提供一个lambda,该lambda具有constexpr int i
上面的一系列工作将整数列表提升到类型列表中,因为只使用类型会使元编程不那么特殊。您可以跳过这一提升,为每个整数编写一个,直接使用包,代码更少,但对我来说似乎没什么用处。这是我能找到的最短的整数th:
#include <iostream>
template<int... Is>
struct Pack;
template <int I> struct B
{
static void foo() { std::cout << I << "\n"; }
};
template<typename PACK> struct unpack;
template<int...Is>
struct unpack<Pack<Is...>>
{
template<template<int> class T>
static void call()
{
using swallow = int[sizeof...(Is)];
(void) swallow{(T<Is>::foo(), 0)...};
}
};
struct A
{
typedef Pack<1,3,5> ints;
static void foo()
{
unpack<ints>::call<B>();
}
};
int main()
{
A::foo();
}
#包括
模板
结构包;
模板结构B
{
静态void foo(){std::cout 1)是不可能的;2)是。谢谢@T.C。我在给定的链接上投票给了你答案,因为它本身就很有趣。但是我不确定这是否适用于这里:它扩展了函数参数,而这里我有模板参数。另外,我也不清楚为什么(void,0)会解析为int.(void,0)
使用有趣的逗号运算符,它的计算结果正好是正确的参数。包的类型是不相关的。只要你有一个包,你就可以通过包扩展来解包。有趣的解决方案。现在我想要编译时迭代。你能解释一下为什么要使用双卷曲括号吗?如果我想计算el的和,怎么样编译时调用函数名,有什么简单的方法吗?谢谢你的回答。这几乎就是我需要的。考虑到我有很多函数,比如zoo、foo、bar、baz等等,有没有一种方法可以传递函数名而不涉及函数指针?@Fabio不太可能。如果你有足够的恶意,你可以使用宏。我会偷取boost::hana样式并调用一个lambda来获取tag键入我自己。@Yakk想画出它的样子吗?类似于ints::for_each([](自动标记){type_t::foo();})
?回答得很好。我不知道C++17Ramburak中会出现折叠表达式,这是最适合我的解决方案,因为我有两组并行解包的索引。现在我必须用上面的lambda建议来适应它。谢谢。我不理解强制转换为void的需要(它无论如何都会编译)。而不是int[],它似乎也与模板swallow(T&&…{}一起工作。为什么在(xxx,0)中使用0?强制转换为void get
template<typename Tail>
void print(Tail tail)
{
cout << tail << endl;
}
template<typename Head, typename ... Tail>
void print(Head head, Tail ... tail)
{
cout << head;
print(tail...);
}
print(1, 3.14, "something", string{"yeye"}, 52);
sum(1, 512, 55, 91);
template<typename InputTuple, std::size_t ... N>
void tupleIteratorImpl(InputTuple& input, std::index_sequence<N...>)
{
// DO WHATEVER YOU WANT HERE, but the structure is
FUNCTION(/* pass all of the template parameters as arguments */, std::get<N>(input)...);
// and FUNCTION has to have the structure of the examples from point 1.
// but with this, you can already do pretty much anything you imagine
// even at compile time
}
template<typename InputTuple, typename Indices = std::make_index_sequence<std::tuple_size<InputTuple>::value>>
void tupleIterator(InputTuple& input)
{
tupleIteratorImpl(input, Indices());
}
for_each_type( [&](auto tag){
constexpr int i = TAG_TYPE(tag){};
// use i
}, ints_as_types_t<ints>{} );
template<class...>struct types{using type=types;};
template <int...Is> struct Pack {};
template<class pack> struct ints_as_types;
template<class pack>
using ints_as_types_t=typename ints_as_types<pack>::type;
template<class T, template<T...>class pack, T...ts>
struct ints_as_types<pack<ts...>> {
using type=types<std::integral_constant<T,ts>...>;
};
using pack = ints_as_types_t<Pack<1,2,3>>;
template<class T>struct tag_t{using type=T; constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag={};
template<class Tag>using type_t=typename Tag::type;
#define TAG_TYPE(...) type_t<std::decay_t<decltype(__VA_ARGS__)>>;
template<class F, class...Ts>
void for_each_type(F&& f, types<Ts...>) {
using discard=int[];
(void)discard{ 0, ((
f(tag<Ts>)
),void(),0)...};
}
for_each_type( [&](auto tag){
constexpr int i = TAG_TYPE(tag){};
// use i
}, ints_as_types_t<ints>{} );
#include <iostream>
template<int... Is>
struct Pack;
template <int I> struct B
{
static void foo() { std::cout << I << "\n"; }
};
template<typename PACK> struct unpack;
template<int...Is>
struct unpack<Pack<Is...>>
{
template<template<int> class T>
static void call()
{
using swallow = int[sizeof...(Is)];
(void) swallow{(T<Is>::foo(), 0)...};
}
};
struct A
{
typedef Pack<1,3,5> ints;
static void foo()
{
unpack<ints>::call<B>();
}
};
int main()
{
A::foo();
}