运行阶段双分派

原创 2007年09月20日 18:44:00

如果你想在运行阶段分派,你将避免暴力手段,因为简单的dynamic_cast底层一样消耗我们的效率。

pair是个不错的东西,它可以把两个东西当成一个用。pair两个类型作为索引可以获得双分派的目标函数,这是最朴素的想法:

template    <class BaseLhs,class BaseRhs,typename ResultType>
class    BasicDispatcher
{
    typedef    pair
<OrderedTypeInfo,OrderedTypeInfo>    KeyType;
        
//pair是一个强有力的工具
    typedef    ResultType    (*CallbackType)(BaseLhs&,BaseRhs&);
    typedef    CallbackType    MappedType;
    map
<KeyType,MappedType>    MapType;
    MapType        callbackMap_;
}
;

模板化的双BasicDispatcher像这样:

template
<
    
class    BaseLhs,
    
class    BaseRhs,
    typename    ResultType,
    typename    CallbackType    
= ResultType    (*)(BaseLhs&,BaseRhs&)
>
class    BasicDispatcher
{
    typedef    pair
<TypeInfo,TypeInfo>        KeyType;
    typedef    CallbackType                MappedType;
    typedef    AssocVector
<KeyType,MappedType>    MapType;
    MapType    callbackMap_;

public:
    template    
<class SomeLhs,class SomeRhs>
    
void    Add(CallbackType    fun)
    
{
        
const    KeyType    key(typeid(SomeLhs),typeid(SomeRhs));
        callbackMap_[key]    
= fun;
    }

    
    ResultType    Go(BaseLhs
& lhs,BaseRhs& rhs)
    
{
        MapType::iterator    i    
= callbackMap_.find(KeyType(typeid(lhs),typeid(rhs)));
        
if (i == callbackMap_.end())
        
{
            
throw    "fun not found";
        }

        
return    (i->second)(lhs,rhs);
    }

}
;

使用起来像这样: 

class MyBase;
class MyA;
class MyB;
typedef    BasicDispatcher
<MyBase,MyBase,void>    Dispatcher;
void    DoSmThing(MyBase& lhs,MyBase rhs)
{
    MyA
&    ra    = dynamic_cast<MyA&>(lhs);
    MyB
&    rb    = dynamic_cast<MyB&>(rhs);
    
//...
}

Dispatcher    disp;
disp.Add
<MyA,MyB>(DoSmThing);

这已经足够好了,但是还是有问题,你只能对已注册的类型进行操作。对于继承的情况,这需要客户转型,这是非常危险和我们不愿看到的,于是有了trampoline的解决方案,它其实是对上述BasicDispatcher的一个包装,但是不需要用户处理转型。

template    <class BaseLhs,class BaseRhs,typename ResultType,class BDispatcher = BasicDispatcher>
class FnDispatcher
{
    BDispatcher
<BaseLhs,BaseRhs,ResultType>    backEnd_;
public:
    template    
<class ConcretLhs,class ConcretRhs,ResultType (*callback)(ConcretLhs&,ConcretRhs)>
    
void    Add()
    
{
        
struct Local 
        
{
            
static    ResultType    Trampoline(BaseLhs& lhs,BaseRhs& rhs)
            
{
                
return    callback(dynamic_cast<ConcretLhs&>(lhs),dynamic_cast<ConcretRhs&>(rhs));
            }

        }
;
        
return    backEnd_.Add(ConcretRhs,ConcretLhs>(&Local::Trampoline));
            
//这太美妙了
    }

}
;

对于对称的问题,也不用在调用的时候进行判断,我们多提供一个方法就可以了:

template    <class ConcretLhs,class ConcretRhs,ResultType (*callback)(ConcretLhs&,ConcretRhs),bool symmetric>
void    Add()
{
    
struct Local 
    
{
        
static    ResultType    Trampoline(BaseLhs& lhs,BaseRhs& rhs)
        
{
            
return    callback(dynamic_cast<ConcretLhs&>(lhs),dynamic_cast<ConcretRhs&>(rhs));
        }

    }
;
    Add
<ConcretLhs,ConcretRhs>(&Local::Trampoline);
    
if (symmetric)
    
{
        Add
<ConcretRhs,ConcretLhs>(&Local::Trampoline);
    }

}

我把这个理解为双分派的map解决方案,你也可以直接使用Loki库享用这个功能,但是了解这底层的细节有助于你处理类似问题的时候获得一个想法,而不是使用现成的东西。Loki给了你一个基本的框架可以使用模仿,但是遇到问题借助它的思想解决问题的情况也非常或者说更普遍,这是我现在使用Loki的感觉,所以更多的时候我想多了解一点这底层的东西,Andrei大脑里的东西。

相关文章推荐

[笔记][Java7并发编程实战手册]3.6 并发阶段任务的运行phaser

[笔记][Java7并发编程实战手册]系列目录简介Phaser是一个更强大的、更复杂的同步辅助类,可以代替CyclicBarrier CountDownLatch的功能,但是比他们更强大。 Phas...

并发编程--并发阶段任务的运行

java并发Api提供了一个

junit源码解析--测试驱动运行阶段

前面的博客里面我们已经整理了junit的初始化阶段,接下来就是junit的测试驱动运行阶段,也就是运行所有的testXXX方法。OK,现在我们开始吧。 前面初始化junit之后,开始执行doRun方...

阶段巨献 - centos+php-fpm+mariaDB+svn+nodejs,配置linux的php和nodejs网站运行环境。

前言对于一个小项目和小公司而言,用php作为开发语言是很理智和聪明的选择,但是只要开发团队超过一个人,并且项目需要长时间持续开发下去,那么,一个相对稳定的运行环境及协同工作环境是必须的。 最近刚好转...
  • cdnight
  • cdnight
  • 2016年11月10日 15:14
  • 1486

JSF运行的6个阶段

JSF是基于事件驱动的,首先介绍JSF的事件侦听。介绍中我仅仅给大家提供简单的场景。不过我需要首先申明,思考这些事件的时候,你最好先用C/S架构下的模式考虑她的运作模式,再用web下js调度动作的方式...

mapreduce运行的5个阶段

mapreduce shuffle运行过程

数据库表表面上存在索引和防错机制,然而一个简单的查询就会耗费很长时间。Web应用程序或许在开发环境中运行良好,但在产品环境中表现同样糟糕。如果你是个数据库管理员,你很有可能已经在某个阶段遇到上述情况。

人们一直在推动MySQL发展到它的极限。这里是100条调节和优化MySQL安装的技巧。一些技巧是针对特定的安装环境的,但这些思路是通用的。我已经把他们分成几类,来帮助你掌握更多MySQL的调节和优化技...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:运行阶段双分派
举报原因:
原因补充:

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