我想编写一个类方法,它接受一个模板参数包,但是零参数,并对类型进行“迭代”:
struct Bar {
template <typename T, typename... Ts>
void foo() {
// something with T that involves Bar's members
foo<Ts...>();
}
};
实现此目的的首选方法是什么?
答案 0 :(得分:3)
您可以使用以下内容:
struct Bar {
template <typename... Ts>
void foo() {
int dummy[] = {0 /*Manage case where Ts is empty*/,
(bar<Ts>(), void() /* To avoid overload `operator,` */, 0)...};
(void) dummy; // suppress warning for unused variable.
}
template <typename T>
void bar()
{
// something with T that involves Bar's members
}
};
在C ++ 17中,可以使用折叠表达式简化它:
struct Bar {
template <typename... Ts>
void foo() {
(static_cast<void>(bar<Ts>()), ...);
}
template <typename T>
void bar()
{
// something with T that involves Bar's members
}
};
答案 1 :(得分:3)
template<class...Fs>
void do_in_order(Fs&&...fs) {
int _[]={0, ( std::forward<Fs>(fs)(), void(), 0 )...};
(void)_;
}
隐藏以从左到右的顺序执行一组函数对象所需的语法。
然后:
struct Bar {
template <class... Ts>
void foo() {
do_in_order([&]{
using T = Ts;
// code
}...);
}
};
在符合标准的编译器中,我们将运行// code
,其中T
是从左到右的每种类型。
请注意,一些声称是C ++ 11编译器的编译器可能无法编译上述内容。
这种技术的优点在于它隐藏了令人讨厌的&#34;扩展和评估模板&#34;具有明确名称的函数中的代码。你只需编写do_in_order
一次,通常几乎每次使用该数组扩展技巧都足够了。
使用这种深奥的语法有两个重要原因而不是&#34;更简单&#34;递归解决方案。
首先,它使优化器更容易。优化器有时会在一堆递归调用后放弃。
其次,传统递归函数的函数签名的长度名称之和在O(n ^ 2)处增长。如果使用帮助程序类型,则名称的总长度也为O(n ^ 2)。除非您小心,否则会导致编译时间,链接时间和二进制大小膨胀。
在C ++ 1z中,有一些&#34; fold&#34;语法可能使上面的深奥部分不那么深奥。
答案 2 :(得分:0)
我喜欢重载函数和使用类型列表:
#include <iostream>
#include <typeinfo>
template <typename ...Ts> struct typelist { };
void foo_impl(typelist<> )
{
// we are finished
}
template <typename T, typename ...Ts>
void foo_impl(typelist<T, Ts...> )
{
std::cout << typeid(T).name() << ", ";
foo_impl(typelist<Ts...>{});
}
template <typename ...Ts>
void foo()
{
std::cout << "called with <";
foo_impl(typelist<Ts...>{});
std::cout << ">" << std::endl;
}
int main()
{
foo<int, char, float>();
}