[英]Variadic template class iterate over types
我试图用一种方法来创建可变参数模板类,该方法需要遍历模板参数并为每种类型调用不相关的模板函数。
该模板类的想法是使用特定的模板参数进行扩展,以封装基本行为。
一个简单的总体思路示例就是这个(可怕的) Checker
类:
class Arg {
Arg() {};
virtual ~Arg() = default;
};
class A : public Arg{ /* ... */ };
class B : public Arg{ /* ... */ };
class C : public Arg{ /* ... */ };
template <typename ... SubClasses>
class Checker {
public:
Checker() {};
virtual ~Checker() = default;
bool isOneOf(Arg* base) const;
};
template <typename ... SubClasses>
bool Checker<SubClasses>::isOneOf(Arg* arg) const
{
// NOTE: I don't know how I would iterate over the class types....
for (auto SubClass : SubClasses...) { // <-- not valid code
if (std::dynamic_cast<SubClass>(arg)) {
return true;
}
}
return false;
}
class Whatever : public Checker<A, B> {};
auto whatever = new Whatever();
auto a = new A();
auto b = new B();
auto c = new C();
whatever->isOneOf(a); // true
whatever->isOneOf(b); // true
whatever->isOneOf(c); // false
为了使isOneOf
正常工作,它需要能够遍历模板参数
我使用的是C ++ 14编译器, 无法使用boost
。
我想可能的C ++ 14解决方案(也是C ++ 11)是
template <typename ... SubClasses>
bool Checker<SubClasses...>::isOneOf (Arg * arg) const
{
using unused = bool[];
bool ret { false };
(void)unused { false, ret |= (nullptr != dynamic_cast<SubClasses *>(arg))... };
return ret;
}
不幸的是,当第一个为true时,就不会触发电路(即:评估所有nullptr != dynamic_cast
测试(如果编译器未对其进行优化))。
如果您可以使用C ++ 17,那么通过模板折叠,一切都将更加简单
template <typename ... SubClasses>
bool Checker<SubClasses...>::isOneOf (Arg * arg) const
{ return (... || (nullptr != dynamic_cast<SubClasses *>(arg)) ); }
template<class T>struct tag_t{using type=T;};
template<class Tag>using type_t=typename Tag::type;
template<class F>
void foreach_arg(F&&f){
return [f=std::forward<F>(f)](auto&&...args){
int discard[]={0,(void(
f(decltype(args)(args)
),0)...};
(void)discard;
};
}
现在:
bool isOneOf(Arg* base) const{
bool r=false;
foreach_arg( [&](auto tag){ r = r || dynamic_cast<type_t<decltype(tag)>>( base ); } )
( tag_t<SubClasses>{}... );
return r;
}
使用C ++ 17,应该可以对折叠表达式进行修补,并一口气完成它。 但是,对于C ++ 14,可能最易读,甚至不是最简洁的方法是使用帮助程序模板类,以及一些专门知识。
#include <iostream>
class Arg {
public:
Arg() {};
virtual ~Arg() = default;
};
template<typename ...Args> struct is_one_of_helper;
template<>
struct is_one_of_helper<> {
static bool isOneOf(Arg *arg)
{
return false;
}
};
template<typename A, typename ...Args>
struct is_one_of_helper<A, Args...> {
static bool isOneOf(Arg *arg)
{
if (dynamic_cast<A *>(arg))
return true;
return is_one_of_helper<Args...>::isOneOf(arg);
}
};
template <typename ... SubClasses>
class Checker {
public:
Checker() {};
virtual ~Checker() = default;
bool isOneOf(Arg* base) const
{
return is_one_of_helper<SubClasses...>::isOneOf(base);
}
};
class A : public Arg{ /* ... */ };
class B : public Arg{ /* ... */ };
class C : public Arg{ /* ... */ };
int main()
{
Arg *a=new A;
Arg *b=new B;
Arg *c=new C;
Checker<B, C> checker;
std::cout << checker.isOneOf(a)
<< std::endl;
std::cout << checker.isOneOf(b)
<< std::endl;
std::cout << checker.isOneOf(c)
<< std::endl;
}
结果输出:
0
1
1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.