每日一題20:與C++11的第一次邂逅——可變參模板與C#委託類比

來源:互聯網
上載者:User

標籤:模板   c#委託   c++11   vector   

這篇文章本來是前天發的,但是不知道為什麼CSDN上沒有顯示,可能是我沒發,記錯了。又由於沒有留底稿,還是重寫一下吧,也為知己不留底稿的惡習做個標記。
之所以接觸C++11是因為自己前天突發奇想想用C++來類比一下C#裡的委託,但是嘗試過很多方法和各種搜尋後,知道之前的C++是不支援模板重載的,所以不可能通過編寫多種版本的模板來實現變參的效果,如果使用《C++設計新思維》裡的TypeList方式的話,我不知道能不能做到,即使能做到也不可能達到預期的效果,並且TypeList是一個重型武器,構建起來比較費時(個人癖好,如果不是為了工程,我會自己構建一個的,否則可以用Loki庫裡面的)。繼續搜尋之後發現,C++11支援變參模板了!所以變參的問題就算解決了。
下一個問題是委託支援=、+=、-=操作符,所以為了讓類比出來的C#委託也支援這些功能,所以需要一個可自動擴充的容器,鏈表其實不錯,但是對於本文的目的,數組就夠了,所以我先做了一個簡單的容器Vector(作為學習沒有使用標準庫裡的vector):

#ifndef _VECTOR_H_#define _VECTOR_H_namespace MyDataStructure{    template<typename T>    class Vector    {    private:        int capacity;        int size_;        T *vals;    private:        void copy(const Vector& v)        {            if (v.capacity != 0)            {                vals = new T[v.capacity];                memcpy(vals, v.vals, v.capacity*sizeof(T));            }            else            {                vals = NULL;            }            capacity = v.capacity;            size_ = v.size_;        }        void destroy()        {            capacity = size_ = 0;            if (vals) delete[]vals;            vals = NULL;        }        void forward_move(int start, int end,int targ)        {            if (start > end) return;            if (targ >= start) return;            while ( start <= end)                vals[targ++] = vals[start++];        }    public:        Vector() : capacity(0), size_(0), vals(NULL){};        Vector(int capacity) : capacity(capacity), size_(0)        {            vals = new T[capacity];            memset(vals, 0, capacity*sizeof(T));        }        Vector(const Vector& v)        {            copy(v);        }        Vector& operator = (const Vector& v)        {            if (this != &v)            {                destroy();                copy(v);            }            return *this;        }        void resize(int capacity)        {            if (capacity <= 0) return;            T* vs = new T[capacity];            if (capacity <= this->capacity)            {                memcpy(vs, this->vals, capacity*sizeof(T));            }            else            {                memset(vs, 0, capacity*sizeof(T));                memcpy(vs, this->vals, this->capacity*sizeof(T));            }            this->capacity = capacity;            this->vals = vs;            if (capacity < this->size_)                size_ = capacity;        }        void push_back(T val)        {            if (capacity == 0)                resize(2);            else if (size_ >= capacity)                resize(capacity * 2);            vals[size_++] = val;        }        const T& operator [](int index) const        {            return vals[index];        }        T& operator[](int index)        {            return vals[index];        }        void clear()        {            size_ = 0;        }        bool empty()        {            return size_ == 0;        }        bool null()        {            return capacity == 0;        }        int size()        {            return size_;        }        void erase(int index)        {            if (index < 0 || index >= size_) return;            forward_move(index + 1, --size_, index);        }        void erase(int start, int end)        {            if (start < 0 || start >= size_) return;            if (end < 0 || end >= size_) return;            if (start > end) return;            forward_move(end + 1, size_ - 1, start);            size_ -= (end - start + 1);        }        int find_first(T val)        {            for (int i = 0; i < size_; ++i)            {                if (vals[i] == val) return i;            }            return -1;        }        int find_last(T val)        {            for (int i = size_ - 1; i >= 0; --i)            {                if (vals[i] == val) return i;            }            return -1;        }        Vector<int> find_all(T val)        {            Vector<int> v;            for (int i = 0; i < size_; ++i)            {                if (vals[i] == val) v.push_back(i);            }            return v;        }    };}#endif

先來類比不含傳回值的委託Action:

#ifndef _ACTION_H_#define _ACTION_H_#include "Vector.h"using namespace MyDataStructure;//聲明中和變參函數差不多,加上...,像下面這樣,這時可以把Types稱為類型包,//編譯器會根據執行個體化模板時自動解析Types到底包含了幾個類型,分別是哪些類//型。template <typename ... Types>class Action{private:     //用類型包聲明一個指示變參函數的函數指標,操作符的支援的關鍵就是它了     //typedef 關鍵字不能省,否則下一句typedef語句非法,因為編譯器不能     //識別function為一個類型,用Types作為函數參數的類型,把paras稱為參     //數包吧    typedef void(*function)(Types...paras);    typedef function func;    Vector<func> funcs;public:    Action& operator = (const func f)    {        funcs.clear();        return (*this += f);    }    Action& operator += (const func f)    {        funcs.push_back(f);        return *this;    }    Action& operator -= (const func f)    {        funcs.erase(funcs.find_last(f));        return *this;    }    //實現委託嘛,當然用C++裡的仿函數了,那麼實現()操作符,    //注意參數聲明形式    void operator()(Types ...paras)    {        int count = funcs.size();        for (int i = 0; i < count; i++)        {             //調用時,講參數包後的...加上,否則編譯器也不能識別,             //正式以這種形式使得編譯器能夠對參數包進行解包的            funcs[i](paras...);        }    }};#endif

接下來,類比具有傳回值的委託Func:

#ifndef _FUNC_H_#define _FUNC_H_#include "Vector.h"using namespace MyDataStructure;//和可變參函數一樣,變參模板允許有幾個確定的參數聲明,但是這些//確定的必須放在可變的參數之前template<typename T1,typename ... Types>class Func{private:    typedef T1 (*function)(Types ...paras);    typedef function func;    Vector<func> funcs;public:    Func& operator = (const func f)    {         funcs.clear();        return (*this += f);    }    Func& operator += (const func f)    {        funcs.push_back(f);        return *this;    }    Func& operator -= (const func f)    {        funcs.erase(funcs.find_last(f));        return *this;    }    //不用太擔心返回Vector拷貝建構函式帶來的開銷,編譯器的NRV最佳化    //會協助我們,當然以這樣的方式作為委託的傳回值未必合理    Vector<T1> operator()(Types ...paras)    {        Vector<T1> v;        int count = funcs.size();        for (int i = 0; i < count; i++)        {            v.push_back(funcs[i](paras...));        }        return v;    }};#endif

類比完畢,看看測試代碼:

// Vector.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include "Vector.h"#include "Action.h"#include "Func.h"#include <iostream>using namespace MyDataStructure;using namespace std;void g1(int a, int b){    cout << a + b << endl;}void g2(int a, int b){    cout << a - b << endl;}void g3(int a, int b){    cout << a * b << endl;}void f1(int p){    cout << p << endl;}void f2(int p){    cout << p*2 << endl;}void f3(int p){    cout << p * 3 << endl;}int F1(){    return 5;}int F2(){    return 10;}int F3(){    return 15;}void Fv1(){    cout << 100 << endl;}void Fv2(){    cout << 200 << endl;}void Fv3(){    cout << 300 << endl;}int _tmain(int argc, _TCHAR* argv[]){    Action<int> ac;    ac += f1;    ac += f2;    ac += f3;    ac(4);    ac -= f1;    ac(5);    Action<> acv;    acv += Fv3;    acv += Fv2;    acv += Fv1;    acv();    Action<int, int> cal;    cal += g1;    cal += g2;    cal += g3;    cal(50, 30);    cal -= g3;    cal(50, 30);    Func<int> fu;    fu += F1;    fu += F2;    fu += F3;    Vector<int> v = fu();    for (int i = 0; i < v.size(); ++i)    {        cout << v[i] << ‘ ‘;    }    cout << endl;    fu -= F1;    v = fu();    for (int i = 0; i < v.size(); ++i)    {        cout << v[i] << ‘ ‘;    }    cout << endl;    return 0;}


運行結果與預期一致,類比成功,在使用方式上,除了對於無傳回值無參數的委託有點不一樣,其他都是一樣的,並且C++類比的委託可以支援的類型個數絕對不止16個,這的看編譯器支援的是多少!這種方式類比委託還是多虧了C++11增加的新特性,否則必定還得話費很多時間才能完成。是時候多瞭解一下C++11了,這一次讓我更喜歡C++這門語言了。

每日一題20:與C++11的第一次邂逅——可變參模板與C#委託類比

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.