亲爱的互联网人士,
我目前正在C ++ 14中编写一个变体类,需要为参数包中的每个元素调用一个模板函数。经过一些搜索,我遇到了this页面,其中包含以下示例。
template<typename... Ts> void func(Ts... args){
const int size = sizeof...(args) + 2;
int res[size] = {1,args...,2};
// since initializer lists guarantee sequencing, this can be used to
// call a function on each element of a pack, in order:
int dummy[sizeof...(Ts)] = { (std::cout << args, 0)... };
}
我创建了这个小例子,展示了我想要实现的目标。
#include <iostream>
template<typename Ta, typename Tb> struct TypeCmp
{
static constexpr bool Value = false;
};
template<typename T> struct TypeCmp<T, T>
{
static constexpr bool Value = true;
};
template<typename T, typename... Ts> struct TypeIdCounter;
template<typename T> struct TypeIdCounter<T>
{
static constexpr size_t Value = 1;
};
template<typename T, typename Tcur, typename... Ts> struct TypeIdCounter<T, Tcur, Ts...>
{
static constexpr size_t Value = sizeof(Tcur)+(TypeCmp<T, Tcur>::Value ? 0 : TypeIdCounter<T, Ts...>::Value);
};
template<typename... Ts> struct TypeHolder
{
template<typename T> struct Info
{
static constexpr size_t Id = TypeIdCounter<T, Ts...>::Value;
static constexpr size_t Size = sizeof(T);
static void Print(size_t id)
{
if (Id == id)
{
std::cout << "Type::Id = " << Id << std::endl;
std::cout << "Type::Size = " << Size << std::endl;
}
}
};
template<typename T> TypeHolder(const T& value) : id(Info<T>::Id)
{
/* copy value to container */
}
void Print() const
{
int dummy[] = {(Info<Ts>::Print(id), 0)...};
if (dummy[0])
{
/* dummy test needed! */
}
}
size_t id;
};
struct Foo
{
std::string name;
int age;
};
typedef TypeHolder<int, long long, bool, Foo> MyTypes;
int main(int argc, char* args[])
{
std::cout << "Id(int): " << MyTypes::Info<int>::Id << std::endl;
std::cout << "Id(bool): " << MyTypes::Info<bool>::Id << std::endl;
std::cout << "Id(Foo): " << MyTypes::Info<Foo>::Id << std::endl;
MyTypes types(true);
types.Print();
return 0;
}
上面列出的程序生成以下输出。
Id(int): 4
Id(bool): 13
Id(Foo): 53
Type::Id = 13
Type::Size = 1
与往常一样,我使用-Wall -Werror
标志编译我的代码。因此需要if (dummy[0])...
条件,否则我会收到unused variable 'dummy'
错误。
我完全不知道为什么int dummy[] = {(Info<Ts>::Print(id), 0)...};
似乎有效,因为Info::Print
是一个void方法。有人可以启发我并解释为什么这有效吗?有没有办法阻止int dummy[] = {(...)}; if (dummy[0]);
技巧而不放弃-Wall -Werror
?
我一直在努力寻找解释,但由于我不知道这种结构甚至被称为什么都不容易找到。
答案 0 :(得分:2)
using dummy=int[];
(void)dummy{0,
((void)(Info<Ts>::Print(id)), 0)...
};
将取代
int dummy[] = {(Info<Ts>::Print(id), 0)...};
并且不应生成任何警告。它还处理0长度列表。
,
运算符将采用void
类型。它是内置的,而且很神奇。
使用上面(void)
旁边的Print
可确保Print
的返回类型为非 - void
,和返回类型重载operator,(blah, 0)
,我们不会出现意外行为。
我自己,在支持它的编译器上,我写了invoke_for_each
。
template<class T>struct tag_type{using type=T;};
template<class T>constexpr tag_type<T> tag{};
template<class F, class...Ts>
void invoke_for_each( F&& f, Ts&&...ts ) {
using dummy=int[];
(void)dummy{0,
((void)(f(std::forward<Ts>(ts)), 0)...
};
};
现在正在使用:
invoke_for_each(
[&](auto tag){
using T=typename decltype(tag)::type;
Info<T>::Print(id);
},
tag<Ts>...
);
我们将魔术阵列的东西移出阅读代码的人的视线。