暴力双分派

原创 2007年09月20日 11:39:00

暴力活是程序员都不想做的,但有的时候你别无选择,但是这种情况下你并不是没有子弹了,暴力可做的事情,多数是类似的重复劳动,C++编译器可以帮我们做这些,只不过你要给编译器一个生成规则,模板是一个描述这种规则的工具。

我来展示一个极其野蛮的行为,有如下4个class:

class MyA;
class MyB;
class MyC;
class MyD;

为了对其双分配,我们需要如下方法:

void    doSomething(MyA&,MyA&);
void    doSomething(MyA&,MyB&);
void    doSomething(MyA&,MyC&);
void    doSomething(MyA&,MyD&);
void    doSomething(MyB&,MyB&);
void    doSomething(MyB&,MyC&);
void    doSomething(MyB&,MyD&);
void    doSomething(MyC&,MyC&);
void    doSomething(MyC&,MyD&);
void    doSomething(MyD&,MyD&);

其实2个或3个类就足以说明这个问题,所以我说这是一件极其野蛮的事情,因为使用了4个类。对于双分派的选择,情况是这样的:

void    DoubleDispach(MyBase& lhs,MyBase& rhs)
{
    
if (MyA* p = dynamic_cast<MyA*>(&lhs))
    
{
        
if (MyA* q = dynamic_cast<MyA*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else if (MyB* q = dynamic_cast<MyB*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else if (MyC* q = dynamic_cast<MyC*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else if(MyD* q = dynamic_cast<MyD*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else
        
{
            doSomething(lhs,rhs);
        }

    }

    
else if(MyB* p = dynamic_cast<MyB*>(&lhs))
    
{
        
if (MyA* q = dynamic_cast<MyA*>(&rhs))
        
{
            doSomething(
*q,*p);
        }

        
else if (MyB* q = dynamic_cast<MyB*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else if (MyC* q = dynamic_cast<MyC*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else if(MyD* q = dynamic_cast<MyD*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else
        
{
            doSomething(lhs,rhs);
        }

    }

    
else if(MyC* p = dynamic_cast<MyC*>(&lhs))
    
{
        
if (MyA* q = dynamic_cast<MyA*>(&rhs))
        
{
            doSomething(
*q,*p);
        }

        
else if (MyB* q = dynamic_cast<MyB*>(&rhs))
        
{
            doSomething(
*q,*p);
        }

        
else if (MyC* q = dynamic_cast<MyC*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else if(MyD* q = dynamic_cast<MyD*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else
        
{
            doSomething(lhs,rhs);
        }

    }

    
else
    
{
        
if (MyA* q = dynamic_cast<MyA*>(&rhs))
        
{
            doSomething(
*q,*p);
        }

        
else if (MyB* q = dynamic_cast<MyB*>(&rhs))
        
{
            doSomething(
*q,*p);
        }

        
else if (MyC* q = dynamic_cast<MyC*>(&rhs))
        
{
            doSomething(
*q,*p);
        }

        
else if(MyD* q = dynamic_cast<MyD*>(&rhs))
        
{
            doSomething(
*p,*q);
        }

        
else
        
{
            doSomething(lhs,rhs);
        }

    }

}

 这真是太野蛮了,是的,我要让你看到的就是这样,实际上,碰到这样的问题,不管最后采用什么手段,最终的代码逻辑都是这样的,现在我们来考虑如何驱动编译器帮我们做这些无聊的事情。

我们必须有如下类型:

template
<
    
class Exec,
    
class LType,
    
class LTList,
    
class RType,
    
class RTList,
    typename    ResultType
>

这是双分派时的参与者们。

使用模板就是驱动编译器生成代码,所以驱动规则的时候请参考你写代码的逻辑,你考虑问题的逻辑被合理分析总结就可以被编译器合理使用,其实,这个过程中想到你是如何想到这个问题的解决方法的过程是非常重要的,语言如此的拗口,实际上,这个思想的行为和语言一样拗口。

按照我们写代码的逻辑,我们需要若干的最终执行者,它们被封装在Exec类里。我们需要lhs类型检索,然后rhs类型检索,如此我们有如下几个方法。

第一次分配:

template
<
    
class Exec,
    
class LType,
    
class LTList,
    
class RType,
    
class RTList,
    typename    ResultType
>
class StaticDispatcher
{
    typedef    typename    LTList::Head    Head;
    typedef    typename    LTList::Tail    Tail;
    
static    ResultType    FirstDispach(LType& lhs,RType& rhs,Exec exc)
    
{
        
if (Head* p1 = dynamic_cast<Head*>(&lhs))
        
{
            
return    
                StaticDispatcher
<Exec,LType,NullType,RType,RTList>::SecondDispach(*p1,rhs,exc);
        }

        
else
        
{
            
return    
                StaticDispatcher
<Exec,LType,Tail,RType,RTList>::FirstDispach(lhs,rhs,exc);
        }

    }

    
static    ResultType    FirstDispach(NullType& lhs,RType& rhs,Exec exc)
    
{
        
return    exc.OnError(lhs,rhs);
    }

}
;

 

如果找不到特定类型(TList走到了NullType),依据偏特化我们进行错误处理。

第二次分派:

template
<
    
class Exec,
    
class LType,
    
class LTList,
    
class RType,
    
class RTList,
        typename    ResultType
>
class StaticDispatcher
{
    typedef    typename    RTList::Head    Head;
    typedef    typename    RTList::Tail    Tail;
    template 
<typename SomeType>
    
static    ResultType    SecondDispach(SomeType& lhs,RType& rhs,Exec exc)
    
{
        
if (Head* p1 = dynamic_cast<Head*>(&rhs))
        
{
            
return    exc.doSomething(lhs,*p1);
        }

        
else
        
{
            
return    
                StaticDispatcher
<Exec,SomeType,NullType,RType,Tail>::SecondDispach(lhs,rhs,exc);
        }

    }

    template    
<typename SomeType>
    
static    ResultType    SecondDispach(SomeType& lhs,NullType& rhs,Exec exc)
    
{
        
return    exc.OnError(lhs,rhs);
    }

}
;

和第一次分派的想法一样。

我用非常朴素的想法描述了双分派的代码,Loki里有更好的东西。

这里有一个问题,就是子类可以合理向基类转换,这就要求我们的TList必须是有特定顺序的,幸好,我们有DerivedToFront工具。

相关文章推荐

【Codeforces Round 345 (Div 1) B】【暴力 双指针】Image Preview 看照片、阅读、移动、反转最多看照片数

Beautiful Paintings time limit per test 1 second memory limit per test 256 megabytes ...

[SCOI2009]生日礼物-暴力-排序-双指针

题目链接:右转进入题目 题目大意:请自行参见题目。 表示完全把这个题当作普及阻难度做的 题目有的条件没有用,没加任何优化都2000ms,比很多题解快。 由于这道题非常简单,有很多中解法...
  • Mys_C_K
  • Mys_C_K
  • 2017年04月02日 22:33
  • 149

暴力破解压缩包密码工具

  • 2017年11月01日 09:35
  • 24.01MB
  • 下载

15万自收藏暴力破解字典

  • 2017年10月06日 20:53
  • 457KB
  • 下载

暴力英语学习法 + 严格的目标管理 = 成功快速靠谱的学好英语

最近想开始学习英语,在网上找到这篇文章写的挺好的。  本文转自:http://www.cnblogs.com/jesse2013/p/how-to-learn-english.html#b01 ...

php暴力破解代码

  • 2015年04月21日 10:54
  • 758B
  • 下载

rar暴力破解工具

  • 2016年04月12日 18:53
  • 51.36MB
  • 下载

HUD 2222 AC自动机摸 解法:1.暴力.2.指针型代码.3.数组型代码

AC自动机都看了一个星期了。也能自己把模板敲出来了。 分享几篇好的博客http://blog.csdn.net/niushuai666/article/details/7002823(AC自动机)这篇...

Unlocker 暴力删除软件

  • 2012年11月05日 15:16
  • 56KB
  • 下载

暴力备份卸载

  • 2014年03月04日 14:30
  • 538KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:暴力双分派
举报原因:
原因补充:

(最多只允许输入30个字)