c++ - 用于初始化派生类型的通用 switch 语句

标签 c++ templates polymorphism

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

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; };

目前我有 4 个 switch 语句,它们都执行非常相似的操作。即对于复制和移动运算符,调用 new 运算符、new 放置。这是需要维护的大量代码。我想要只有 1 个 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;
}

如您所见,除了对结构类型的依赖之外,每种情况都是相同的。这对我来说是"template",但我不知道如何传递对象。

我是否仅限于编码 4 个开关,或者有什么办法吗?请不要引用“Boost”,此代码必须独立于任何其他库。

解决方案:(感谢 Jan Hudec)

template< template < class > class Action >
typename Action< Struct< DNS_Q_A >::Type >::result_type
    CreateRecord ( 
        unsigned n,
        typename Action< Struct< DNS_Q_A >::Type >::first_argument_type arg1,
        typename Action< Struct< DNS_Q_A >::Type >::second_argument_type arg2 )
{
    typedef typename typename Action< Struct< DNS_Q_A >::Type >::result_type ReturnType;
    switch ( n )
    {
    case DNS_Q_A:       return static_cast< ReturnType >( Action< Struct< DNS_Q_A >::Type >()( arg1, arg2 ) );
    case DNS_Q_NS:      return static_cast< ReturnType >( Action< Struct< DNS_Q_NS >::Type >()( arg1, arg2 ) );
    /*...*/
    }
}

Action 结构定义为:

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 ) ) );
    }
};

并将 Switch 语句替换为:

pInstance = CreateRecord< Copy >( nType, Container, Other );

最佳答案

您可以创建一个函数模板,该模板将采用仿函数模板来执行。如果没有 C++11 可变参数,所有仿函数都需要相同数量的参数,因此您必须将它们打包在结构中,或者在它们不相关时传递 NULL。使用可变参数模板(我还没有使用过它们,所以我不记得确切的语法,也不会在这里写它们),您可以轻松地在每种形式中拥有不同的参数。

这个想法就像(我的想法,所以可能有一些错别字):

template <template <typename T> class F>
F<Struct<DNS_Q_A>::Type>::return_type RecordCall(RecordType nType, const F<Struct<DNS_Q_A>::Type>::argument_type &arg)
{
    switch(nType)
    {
        case DNS_Q_A:
            return F<Struct<DNSK_Q_A>::Type>()(arg);
        case DNS_Q_CNAME:
            return F<Struct<DNSK_Q_CNAME>::Type>()(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));
    }
}

并结合在一起:

target = RecordCall<Clone>(source->GetType(), source);

(并包装在另一个函数中,它将插入多参数形式的 getter 和/或打包参数,例如放置复制构造)

虽然复制的常用方法是使用虚拟 Clone 成员方法。但这不适用于建筑。

编辑:请注意,我将内部模板中的返回类型和参数类型定义为 typedef(使用标准 unary_function 帮助器),但它们也可以作为单独的模板参数传递,特别是如果RecordCall 的使用将被包装在另一个函数中。也许返回类型甚至不必是模板参数,因为对于问题中提到的所有情况,它都将是 Record *

关于c++ - 用于初始化派生类型的通用 switch 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11201428/

相关文章:

c++ - 编译错误 C++ 模板函数以迭代器作为参数

c++ - 从基础对象(智能)指针复制派生对象

C++ 无法访问抽象类 vector 的元素?

C++ : Calling inherited static method from static method

C++11:不带复制构造函数的自定义基于范围的循环

c++ - 哪个功能结构更好?

c++ - 运行时在 boost::mpl::vector 中找到第一个匹配项

c++ - 在 Mac 上的 Xcode 上尝试 C++ - ERROR-exc_bad_access (code=1 address=0x100500000)

c++ - 模板继承类派生基赋值

c++ - 模板特化方法