我想为几种可能类的几种组合编写基准代码。如果我自己编写每个组合,它就会变得无法维护。因此,我正在寻找一种通过模板自动组合每种类型的方法,类似于以下伪代码:
for (typename HashFuction : Sha256, Sha512, Sa512_256, Sha3_256, Sha3_512) {
for (typename KeyingWrapper : TwoPassKeyedHash, OnePassKeyedHash, PlainHash) {
for (typename InstantiatedGetLeaf: GetLeaf<8>, GetLeaf<1024>) {
for (typename algorithm : algA, algB, algC) {
runAndTime<HashFunction,KeyingWrapper,
InstantiatedGetLeaf,algorithm>(someArgs);
}
}
}
}
其中 Sha256
,... ,TwoPassKeyedHash
,... 是类型。
我正在寻找的代码在功能上应该等同于以下内容:
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<8>,algA>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<8>,algB>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<8>,algC>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<1024>,algA>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<1024>,algB>(someArgs);
runAndTime<Sha256,TwoPassKeyedHash,GetLeaf<1024>,algC>(someArgs);
runAndTime<Sha256,OnePassKeyedHash,GetLeaf<8>,algA>(someArgs);
runAndTime<Sha256,OnePassKeyedHash,GetLeaf<8>,algB>(someArgs);
runAndTime<Sha256,OnePassKeyedHash,GetLeaf<8>,algC>(someArgs);
// And 99 further lines…
在 Peregring-lk 的帮助下,我做到了
#include <iostream>
template<typename Aux_type>
void test_helper()
{}
template<typename Aux_type, typename Head, typename... Tail>
void test_helper() {
std::cout << Head::i;
test_helper<Aux_type, Tail...>();
}
template<typename... Args>
void test()
{
test_helper<void, Args...>();
}
struct A{
static const int i=1;
};
struct B{
static const int i=2;
};
int main() {
test<A, B>();
return 0;
}
但我还不知道如何迭代该递归以获得嵌套循环。任何帮助将不胜感激。
(编辑:代码重构和包含 Peregring-lk 的答案。)
最佳答案
有时了解您的目标会有所帮助:
- 你需要几种参数类型
- 对于每个参数类型,几个可能的“值”
并且想要对每个值的组合应用一些东西(一次每个参数类型一个)。
这看起来可以表达:
combine<
Set<Sha256, Sha512, Sa512_256, Sha3_256, Sha3_512>,
Set<TwoPassKeyedHash, OnePassKeyedHash, PlainHash>,
Set<GetLeaf<8>, GetLeaf<1024>>,
Set<algA, algB, algC>
>(runAndTime);
如果 runAndTime
是以下的实例:
struct SomeFunctor {
template <typename H, typename W, typename L, typename A>
void operator()(cons<H>{}, cons<W>{}, cons<L>{}, cons<A>{});
};
和缺点
只是一种将类型作为常规参数传递的方法(更容易)。
我们走吧?
首先,一些传递类型的方法(便宜):
template <typename T>
struct cons { using type = T; };
template <typename... T>
struct Set {};
显式绑定(bind)
(内部没有魔法):
template <typename F, typename E>
struct Forwarder {
Forwarder(F f): inner(f) {}
template <typename... Args>
void operator()(Args... args) { inner(cons<E>{}, args...); }
F inner;
}; // struct Forwarder
现在我们深入研究手头的实际任务:
- 我们需要迭代类型集
- 在一个集合中,我们需要迭代它的元素(还有类型)
这需要两个级别的调度:
template <typename FirstSet, typename... Sets, typename F>
void combine(F func);
template <typename Head, typename... Tail, typename... Sets, typename F>
void apply_set(F func, Set<Head, Tail...>, Sets... others);
template <typename... Sets, typename F>
void apply_set(F func, Set<>, Sets... others);
template <typename E, typename NextSet, typename... Sets, typename F>
void apply_item(F func, cons<E>, NextSet, Sets...);
template <typename E, typename F>
void apply_item(F func, cons<E> e);
其中 combine
是外部(公开的)函数,apply_set
用于迭代集合,apply_item
用于迭代一组中的类型。
实现很简单:
template <typename Head, typename... Tail, typename... Sets, typename F>
void apply_set(F func, Set<Head, Tail...>, Sets... others) {
apply_item(func, cons<Head>{}, others...);
apply_set(func, Set<Tail...>{}, others...);
} // apply_set
template <typename... Sets, typename F>
void apply_set(F, Set<>, Sets...) {}
template <typename E, typename NextSet, typename... Sets, typename F>
void apply_item(F func, cons<E>, NextSet ns, Sets... tail) {
Forwarder<F, E> forwarder(func);
apply_set(forwarder, ns, tail...);
}
template <typename E, typename F>
void apply_item(F func, cons<E> e) {
func(e);
} // apply_item
template <typename FirstSet, typename... Sets, typename F>
void combine(F func) {
apply_set(func, FirstSet{}, Sets{}...);
} // combine
对于apply_set
和apply_item
中的每一个,我们都有一个递归案例和一个基本案例,尽管这里是某种共同递归,如apply_item
回调到 apply_set
。
还有一个简单的例子:
struct Dummy0 {}; struct Dummy1 {}; struct Dummy2 {};
struct Hello0 {}; struct Hello1 {};
struct Tested {
Tested(int i): value(i) {}
void operator()(cons<Dummy0>, cons<Hello0>) { std::cout << "Hello0 Dummy0!\n"; }
void operator()(cons<Dummy0>, cons<Hello1>) { std::cout << "Hello1 Dummy0!\n"; }
void operator()(cons<Dummy1>, cons<Hello0>) { std::cout << "Hello0 Dummy1!\n"; }
void operator()(cons<Dummy1>, cons<Hello1>) { std::cout << "Hello1 Dummy1!\n"; }
void operator()(cons<Dummy2>, cons<Hello0>) { std::cout << "Hello0 Dummy2!\n"; }
void operator()(cons<Dummy2>, cons<Hello1>) { std::cout << "Hello1 Dummy2!\n"; }
int value;
};
int main() {
Tested tested(42);
combine<Set<Dummy0, Dummy1, Dummy2>, Set<Hello0, Hello1>>(tested);
}
哪个you can witness live on Coliru打印:
Hello0 Dummy0!
Hello1 Dummy0!
Hello0 Dummy1!
Hello1 Dummy1!
Hello0 Dummy2!
Hello1 Dummy2!
享受 :)
注意:假定仿函数的复制成本较低,否则可以使用引用,无论是在传递还是将其存储在 Forwarder
中时。
编辑:删除了 Set
周围的 cons
(它出现的所有地方),这是不必要的。
关于c++ - For 遍历模板参数/类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24015710/