Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 初始化派生类型的泛型switch语句_C++_Templates_Polymorphism - Fatal编程技术网

C++ 初始化派生类型的泛型switch语句

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

我正在创建一个DNS名称解析程序。在解析返回的数据包时,我读取RR类型,然后将其通过开关来初始化派生类型的类记录。记录类型是一种大型枚举类型。我使用模板专门化将枚举映射到结构

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_cast::Type&>(other));},然后在围绕该函数模板的包装器中编写分派。(我假设A、CNAME等都是某个基类的子类,另一个是该基类的实例?)A、CNAME等都是从抽象类记录派生的。另一个是派生类型或基类型的实例。管理员处理这些情况以及类型不匹配。我是从你的建议开始的,但是Switch()函数需要一个带有虚拟成员的公共基类型,而虚拟成员不能是模板。看起来Jan Hudec正在写答案,所以我宁愿等待。
template <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);