⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 multimethods.h

📁 loki 程序库
💻 H
📖 第 1 页 / 共 2 页
字号:
////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
//     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author or Addison-Wesley Longman make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// Last update: August 9, 2002

#ifndef MULTIMETHODS_INC_
#define MULTIMETHODS_INC_

#include "Typelist.h"
#include "LokiTypeInfo.h" //### BCB
#include "Functor.h"
#include "AssocVector.h"
#include <iostream> // ***

////////////////////////////////////////////////////////////////////////////////
// IMPORTANT NOTE:
// The double dispatchers implemented below differ from the excerpts shown in
// the book - they are simpler while respecting the same interface.
////////////////////////////////////////////////////////////////////////////////

namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template InvocationTraits (helper)
// Helps implementing optional symmetry
////////////////////////////////////////////////////////////////////////////////

    namespace Private
    {
/* ### BCB checks existence Fire(rhs, lhs) even when this function is not 
needed, fails to compile
        template <class SomeLhs, class SomeRhs,
			class Executor, typename ResultType>
        struct InvocationTraits
        {
            static ResultType
	    DoDispatch(SomeLhs& lhs, SomeRhs& rhs,
			Executor& exec, Int2Type<false>)
            {
                return exec.Fire(lhs, rhs);
            }
            static ResultType
	    DoDispatch(SomeLhs& lhs, SomeRhs& rhs,
			Executor& exec, Int2Type<true>)
            {
                return exec.Fire(rhs, lhs);
            }
        };
*/
        template <class SomeLhs, class SomeRhs, class Executor, typename
ResultType>
        struct NormalInvocation
        {
            static ResultType DoDispatch(SomeLhs& lhs, SomeRhs& rhs, 
Executor& exec)
            {
                return exec.Fire(lhs, rhs);
            }
        };

        template <class SomeLhs, class SomeRhs, class Executor, typename 
ResultType>
        struct SwappedInvocation
        {
            static ResultType DoDispatch(SomeLhs& lhs, SomeRhs& rhs, 
Executor& exec)
            {
                return exec.Fire(rhs, lhs);
            }
        };
    }


////////////////////////////////////////////////////////////////////////////////
// class template StaticDispatcher
// Implements an automatic static double dispatcher based on two typelists
////////////////////////////////////////////////////////////////////////////////

    template
    <
        class Executor,
        class BaseLhs,
        class TypesLhs,
        bool symmetric = true,
        class BaseRhs = BaseLhs,
        class TypesRhs = TypesLhs,
        typename ResultType = void
    >
    class StaticDispatcher
    {
        template <class SomeLhs>
        static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
            Executor exec, NullType)
        { return exec.OnError(lhs, rhs); }

        template <class TList, class SomeLhs>
        static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
            Executor exec, TList)
        {
            typedef typename TList::Head Head;
            typedef typename TList::Tail Tail;

            if (Head* p2 = dynamic_cast<Head*>(&rhs))
            {
                //### BCB - original statement was too complex for this compiler
                enum { val1 = int(TL::IndexOf<TypesRhs, Head>::value) };
                enum { val2 = int(TL::IndexOf<TypesLhs, SomeLhs>::value) };
                enum { val3 = symmetric && (val1 < val2) };
                // BCB doesn't properly converts enum to bool
                enum { val4 = val3 != 0 };
                const bool val5 = (val4 == 0) ? false : true; // it must be so clumsy

                typedef Private::NormalInvocation<SomeLhs, Head, Executor, ResultType> t1;
                typedef Private::SwappedInvocation<SomeLhs, Head, Executor, ResultType> t2;
                typedef Select<val4, t1, t2>::Result invocation_t;
                return invocation_t::DoDispatch(lhs, *p2, exec);
            }
            return DispatchRhs(lhs, rhs, exec, Tail());
        }

        static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
            Executor exec, NullType)
        { return exec.OnError(lhs, rhs); }

        template <class TList>
        static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
            Executor exec, TList)
        {
            typedef typename TList::Head Head;
            typedef typename TList::Tail Tail;

            if (Head* p1 = dynamic_cast<Head*>(&lhs))
            {
                return DispatchRhs(*p1, rhs, exec, TypesRhs());
            }
            return DispatchLhs(lhs, rhs, exec, Tail());
        }

    public:
        static ResultType Go(BaseLhs& lhs, BaseRhs& rhs,
            Executor exec)
        { return DispatchLhs(lhs, rhs, exec, TypesLhs()); }
    };

////////////////////////////////////////////////////////////////////////////////
// class template BasicDispatcher
// Implements a logarithmic double dispatcher for functors (or functions)
// Doesn't offer automated casts or symmetry
////////////////////////////////////////////////////////////////////////////////

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

        void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun);
        bool DoRemove(TypeInfo lhs, TypeInfo rhs);

    public:
        template <class SomeLhs, class SomeRhs>
        void Add(CallbackType fun)
        {
            DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun);
        }

        template <class SomeLhs, class SomeRhs>
        bool Remove()
        {
            return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
        }

        ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
    };

    // Non-inline to reduce compile time overhead...
    template <class BaseLhs, class BaseRhs,
		typename ResultType, typename CallbackType>
    void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
    	 ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun)
    {
        callbackMap_[KeyType(lhs, rhs)] = fun;
    }

    template <class BaseLhs, class BaseRhs,
		typename ResultType, typename CallbackType>
    bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
         ::DoRemove(TypeInfo lhs, TypeInfo rhs)
    {
        return callbackMap_.erase(KeyType(lhs, rhs)) == 1;
    }

    template <class BaseLhs, class BaseRhs,
		typename ResultType, typename CallbackType>
    ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
               ::Go(BaseLhs& lhs, BaseRhs& rhs)
    {
    	typename MapType::key_type k(typeid(lhs),typeid(rhs));
        typename MapType::iterator i = callbackMap_.find(k);
        if (i == callbackMap_.end())
        {
            std::cout << "Function not found\n";

//                throw std::runtime_error("Function not found");
        }
        return (i->second)(lhs, rhs);
    }

////////////////////////////////////////////////////////////////////////////////
// class template StaticCaster
// Implementation of the CastingPolicy used by FunctorDispatcher

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -