C++实现委托机制(三)——lambda表达式封装

C++实现委托机制(三)——lambda表达式封装1.引言:

             其实原本没打算写这一章的,不过最后想了想,嗯还是把lambda表达式也一并封装进去,让这个委托也适应lambda表达式的注册。不过在之前还是需要先了解lambda表达式。

2.lambda表达式:

             如果大家还有对lambda表达式不了解的可以先去了解lambda表达式的基本语法和用法。这里我们只讲跟lambda表达式封装相关的知识。我们先来看看使用lambda表达式的好处吧:1.lambda表达式可以使得在使用的地方定义相关函数,这样给阅读代码带来一定的方便。2.lambda表达式用法相当函数对象(其实可以说就是一个函数对象不过有点区别)这样就可以和很多函数适配符相结合使用。3.lambda表达式可以获取其作用域的任何动态变量。
        以下是我经过试验后得出个人的观点:
        c++对于lambda表达式的处理应该是当作一个匿名仿函数对象处理。并且其重载operator()函数被申明为const,也就说在定义lambda表达式的时候其封包进去的变量并不是作为这这个类的成员变量,可能是作为一个作为一个绑定值传入的。并且不能用这个lambda表达式推演的类型定义新的对象,否则所有封包进去的变量都会丢失。换句话意思就是一个lambda表达式作为一个函数对象且该类型对象唯一。
        每次显示定义一个lambda表达式都是一个新的类型,即便是这两个表达式完全一样!!如果对于某一个特定的lambda表达式你想多次当作参数传入并且类型唯一,那么你最好选择使用一个变量存下这个lambda表达式(变量类型可以使用auto自动推断)。

3.lambda表达式封装委托:
          嗯其实大家看了上面的lambda表达式后其实会发现对于lambda表达式可以看作是注册这对象的operator()这个成员函数,只不过这个成员函数是const。所以说我们需要在我们的成员函数特化新加一个const版本:
//成员函数委托特化const版
    template<typename T, typename _Ret, typename ..._Args>
    class CMethodDelegate<T, _Ret(T:: *)(_Args...)const> :
        public IDelegate<_Ret, _Args...>
    {
    public:
        typedef _Ret(T::*Method)(_Args...)const;

        CMethodDelegate(T * _object,const Method _method) : mObject(_object), mMethod(_method) { }

        virtual bool isType(const std::type_info& _type) { return typeid(CMethodDelegate<T, _Ret(T:: *)(_Args...)const>) == _type; }

        virtual _Ret invoke(_Args...params)
        {
            return (mObject->*mMethod)(params...);
        }

        virtual bool compare(IDelegate<_Ret, _Args...> *_delegate) const
        {
            if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate<T, _Ret(T:: *)(_Args...)const>))) return false;
            CMethodDelegate<T, _Ret(T:: *)(_Args...)const>* cast = static_cast<CMethodDelegate<T, _Ret(T:: *)(_Args...)const>*>(_delegate);
            return cast->mObject == mObject && cast->mMethod == mMethod;
        }

        CMethodDelegate(){}
        virtual ~CMethodDelegate(){}
    private:
        T * mObject;
        Method mMethod;
    };
          嗯,类型封装好了但是需要给出生成委托的接口,我们还是希望传入lambda表达式(也可以是lambda表达式类型的对象)后能够自动推断其参数类型、返回值类型。但是这个时候我们需要考虑一个问题就是,普通函数的生成接口也是一个参数,lambda表达式的生成接口也是一个参数。然而这两个生成委托的方法却不一样,这就是需要我们考虑如何重载的问题,最后我给出一个写好的代码:
    //生成所有普通函数、成员静态函数委托的接口
    template< typename Ret, typename ...Params>
    CStaticDelegate<Ret(*)(Params...)>* newDelegate(Ret(*func)(Params...))
    {
        return new CStaticDelegate<Ret(*)(Params...)>(func);
    }
    //生成所有成员非静态函数委托的接口
    template< typename T,typename F>
    CMethodDelegate<T,F>* newDelegate(T * _object, F func)
    {
        return new CMethodDelegate<T, F>(_object, func);
    }
    //生成所有函数对象委托的接口
    template< typename T>
    CMethodDelegate<T, decltype(&T::operator())>* newDelegate(T& func)
    {
        return new CMethodDelegate<T, decltype(&T::operator())>(&func, &T::operator());
    }
          这样的话我们就可以使用newDelegate(lambda表达式)来使用了。

4.多播委托委托的使用方法:
          如何创建多播委托,多播委托的就是可以注册多个对象,那么我们先定义一个多播委托:

    CMultiDelegate<void,int> e1;              //void(int)
    CMultiDelegate<void> e2;                  //void()
    CMultiDelegate<int,int,double> e3;        //int(int,double)
        可见定义的类型就是决定可以注册的函数类型。
     使用 += 和 -= 可以注册和注销一个委托。

     对于成员函数第一个参数类型为对象指针,如果需要创建一个临时变量指针请不要使用new T(),请使用 &T().
    还有就是对于lambda表达式的注册和注销有需要值得注意的地方就是,如果你后期可能会对lambda表达式进行注销的话请不要直接传入lambda表达式,请先用一个对象存下该函数对象,然后注册和注销请传入该对象。
int _tmain(int argc, _TCHAR* argv[])
{
    CMultiDelegate<void,int> e;              //void(int)

    e += newDelegate([](int a){ printf("这是lambda表达式\n"); });  //请尽量不要使用这种方式。
    e -= newDelegate([](int a){ printf("这是lambda表达式\n"); });  //这样是无法注销的。因为上面那个lambda表达式和下面这个类型不一样!!
    //请使用下面这种方式:
    auto func = newDelegate([](int a){ printf("这是lambda表达式\n"); });;

    e += func;
    e -= func;

    return 0;
}

        基本上委托就封装到这里了。

原文地址:https://www.cnblogs.com/leijiangtao/p/12059510.html

时间: 2024-10-08 03:18:37

C++实现委托机制(三)——lambda表达式封装的相关文章

lambda表达式封装对数据库的查询

前言: 1.为什么要封装lambda表达式数据库查询,原因有一下几点: 1.1.在以往的开发中进行数据库表查询时,其实所需要的字段就是其中几个,但是在开发中,开发者往往习惯select * 进行查询,当数据多和用户量多时,查询的效率会降低. 1.2.在写查询where条件的时候,总是用string.format去拼接字符串,开发效率低. 1.3.代码不够优雅,代码中嵌套和多sql语句,如果是表字段发生改变时编译器检查不出来,代码出错的概率大. 1.4.本着 write less  do more

委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件

1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委托代表了具有相同参数列表和返回值的所有函数. [csharp] view plaincopy class Program { delegate int CalculateDelegate(int a, int b); int add(int a, int b) { return a + b; } s

兰姆达表达式Lambda 表达式(C# 编程指南)

转https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.Lambda 表达式对于编写 LINQ 查询表达式特别有用. 若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块.例如,lambda 表达式 x => x

Lambda 表达式(C# 编程指南) 微软microsoft官方说明

Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数. Lambda 表达式对于编写 LINQ 查询表达式特别有用. 若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块. 例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值. 如下

如何快速使用Lambda 表达式(C# )

Lambda 表达式是一种可用于创建 委托 或 表达式目录树 类型的 匿名函数 . 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数. Lambda 表达式对于编写 LINQ 查询表达式特别有用. 若要创建 Lambda 表达式,需要在 Lambda 运算符 =>左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块. 例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值. 如下面的示例所示,你可以将此表达式分配给委

Lambda表达式浅析

Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.Lambda 表达式对于编写 LINQ 查询表达式特别有用. 创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块.例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方值. 如下面的示例所示,你可以将此表达式分配给委托类型: deleg

(zz)Lambda 表达式(C# 编程指南)

https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.Lambda 表达式对于编写 LINQ 查询表达式特别有用. 若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块.例如,lambda 表达式 x => x

编写高质量代码改善C#程序的157个建议——建议27:在查询中使用Lambda表达式

建议27:在查询中使用Lambda表达式 LINQ实际上是基于扩展方法和Lambda表达式的.任何LINQ查询都能通过扩展方法的方式来代替. var personWithCompanyList = from person in personList select new { PersonName = person.Name, CompanyName = person.CompanyID==0?"Micro":"Sun" }; foreach (var item in

ASP.NET MVC学前篇之Lambda表达式、依赖倒置

前言 随着上篇文章的阅读,可能有的朋友会有疑问,比如(A.Method(xxx=>xx>yy);)类似于这样的函数调用语句,里面的xxx=>xx>yy这些到底是怎么用的? 依赖倒置原则的实现也会在本篇幅的最后来粗略的讲解一下. 本篇没有核心的主题,如果说要强制定义的话就是这些内容都是基础知识,是为了后续学习MVC框架做铺垫. 1 Lambda Lambda表达式在日常的开发中很常见,使用Lambda表达式可以自由的定义函数体并且精简代码量,那么Lambda表达式是什么呢? Lamb