C++ 初始化派生类型的泛型switch语句
我正在创建一个DNS名称解析程序。在解析返回的数据包时,我读取RR类型,然后将其通过开关来初始化派生类型的类记录。记录类型是一种大型枚举类型。我使用模板专门化将枚举映射到结构C++ 初始化派生类型的泛型switch语句,c++,templates,polymorphism,C++,Templates,Polymorphism,我正在创建一个DNS名称解析程序。在解析返回的数据包时,我读取RR类型,然后将其通过开关来初始化派生类型的类记录。记录类型是一种大型枚举类型。我使用模板专门化将枚举映射到结构 template < QueryType n > struct Struct; template <> struct Struct< DNS_Q_A > { typedef A Type; }; template <> struct Struct< DNS_Q_CNA
template < QueryType n >
struct Struct;
template <> struct Struct< DNS_Q_A > { typedef A Type; };
template <> struct Struct< DNS_Q_CNAME > { typedef CNAME Type; };
template < QueryType n > struct Struct { typedef UNKNOWN Type; };
模板
struct-struct;
模板结构struct{typedef A Type;};
模板结构struct{typedef CNAME Type;};
模板struct struct{typedef UNKNOWN Type;};
目前我有4个switch语句,它们都做了非常类似的事情。即呼叫操作员new,placement new,用于复制和移动任务。这需要维护很多代码。我希望只有一个switch语句,在这里我可以传递一些类型的对象,其中包含要执行的函数、返回类型和n个参数
switch语句如下所示:
switch ( nType )
{
case DNS_Q_A:
pInstance = new ( &Container ) Struct< DNS_Q_A >::Type( dynamic_cast< const Struct< DNS_Q_A >::Type& >( Other ) );
break;
case DNS_Q_CNAME:
pInstance = new ( &Container ) Struct< DNS_Q_CNAME >::Type( dynamic_cast< const Struct< DNS_Q_CNAME >::Type& >( Other ) );
break;
}
开关(nType)
{
案例DNS_Q_A:
pInstance=new(&Container)Struct::Type(dynamic\u cast::Type&>(其他));
打破
案例名称:
pInstance=new(&Container)Struct::Type(dynamic\u cast::Type&>(其他));
打破
}
如您所见,除了依赖结构类型之外,每种情况都是相同的。这对我来说是“模板”,但我不知道如何传入对象
我是否仅限于编码4个开关,还是有办法?请不要引用“Boost”,此代码必须独立于任何其他库
解决方案:(感谢Jan Hudec)
templateclass-Action>
类型名操作::类型>::结果类型
CreateRecord(
未签名的n,
typename操作::Type>::第一个参数\u类型arg1,
类型名操作::类型>::第二个参数\u类型arg2)
{
typedef typename typename操作::Type>::结果类型返回类型;
开关(n)
{
案例DNS_Q_A:返回静态_cast(操作::Type>()(arg1,arg2));
案例DNS\u Q\u NS:返回静态类型转换(操作::Type>()(arg1,arg2));
/*...*/
}
}
操作结构定义为:
template < typename T >
struct Copy : std::binary_function< storage_type&, const Record&, Record* >
{
Record* operator() ( storage_type& Storage, const Record& Obj )
{
return new ( &Storage ) T( dynamic_cast< const T& >( Obj ) );
}
};
template < typename T >
struct Move : std::binary_function< storage_type&, Record&&, Record* >
{
Record* operator() ( storage_type& Storage, const Record& Obj )
{
return new ( &Storage ) T( dynamic_cast< const T& >( std::move( Obj ) ) );
}
};
模板
结构副本:std::二进制函数<存储类型&,常量记录&,记录*>
{
记录*运算符()(存储类型和存储、常量记录和对象)
{
返回新的(&存储)T(动态_cast(Obj));
}
};
模板
结构移动:标准::二进制函数<存储类型&,记录&&,记录*>
{
记录*运算符()(存储类型和存储、常量记录和对象)
{
返回新的(&存储)T(动态转换(std::move(Obj));
}
};
和Switch语句替换为:
pInstance = CreateRecord< Copy >( nType, Container, Other );
pInstance=CreateRecord(nType、容器、其他);
我必须承认,我不太明白通过。。。哑虚拟函数
class Object {
public:
virtual Object* clone() const = 0;
virtual void clone(Container& c) const = 0;
// ...
};
class A: public Object {
public:
virtual A* clone() const override { return new A(*this); }
virtual void clone(Container& c) const override { new (&c) A(*this); }
// ...
};
然后。。。只要摆脱开关:
pInstance = other.clone(container);
工作已经完成。您可以创建一个函数模板,该模板将使用functor模板执行。如果没有C++11可变参数,所有函子都需要相同数量的参数,因此您必须将它们打包到一个结构中,或者在它们不相关时传递null。使用可变模板(我还没有使用它们,所以我不记得确切的语法,也不会在这里写它们),您可以很容易地在每种形式中使用不同的参数 这个想法就像(我脑子里想不出来,所以可能会有一些打字错误):
模板
F::return\u type RecordCall(RecordType nType,const F::argument\u type&arg)
{
交换机(nType)
{
案例DNS_Q_A:
返回F()(arg);
案例名称:
返回F()(arg);
// ...
}
}
现在,您可以编写单独的函数,如:
template <typename T>
struct Clone : std::unary_function<BaseType *, const BaseType *>
{
BaseType *operator()(const BaseType *source)
{
return new<T>(dynamic_cast<const BaseType &>(*source));
}
}
模板
结构克隆:std::一元函数
{
BaseType*运算符()(常量BaseType*源)
{
返回新的(动态_cast(*source));
}
}
并结合起来:
target = RecordCall<Clone>(source->GetType(), source);
target=RecordCall(source->GetType(),source);
(并封装在另一个函数中,该函数将插入多参数形式(如placement copy构造)的getter和/或pack参数)
不过,对于复制,通常的方法是使用虚拟克隆成员方法。但这对建筑业是行不通的
编辑:注意,我将内部模板中的返回类型和参数类型定义为typedefs(使用标准的
unary_函数
helper),但是它们也可以作为单独的模板参数传递,特别是当RecordCall
的使用将被包装到另一个函数中时。对于问题中提到的所有情况,返回类型甚至不必是模板参数,因为它将是Record*
。您的代码可以使用C++11功能吗?具体来说,可变模板会使事情更易于使用。我对VS2010的C++11进行了限制,不幸的是可变模板不受支持。您可以从模板BaseType*doit(ContainerType&container,BaseType&other){return new(&container)Struct::Type(dynamic_casttemplate <typename T>
struct Clone : std::unary_function<BaseType *, const BaseType *>
{
BaseType *operator()(const BaseType *source)
{
return new<T>(dynamic_cast<const BaseType &>(*source));
}
}
target = RecordCall<Clone>(source->GetType(), source);