簡體   English   中英

C ++將運算符[]級聯為operator()參數列表?

[英]C++ cascaded operator[] to operator() parameter list?

我有一個帶有operator()的類,如下所示:

struct S
{
    int operator()(int a, int b, int c, int d);
};

用法示例:

S s;
int i = s(1, 2, 3, 4);

我需要我的用戶能夠使用其他語法:

int i = s[1][2][3][4]; // equivalent to calling s(1, 2, 3, 4)

我知道我需要添加S::operator[](int a) ,並且它需要返回一個輔助對象。 但是除此之外,這一切都變得有些復雜,我覺得我正在重新發明輪子,因為其他庫(例如多維數組)可能已經提供了類似的接口。

理想情況下,我只會使用現有的庫來實現此目標。 失敗了,如何用最通用的代碼實現我的目標?

編輯:理想情況下,我希望在現代優化編譯器上實現此目標而不會增加運行時間。

開始了!

首先,代碼有點雜亂無章-我必須在執行過程中累積參數值,而我能想到的唯一方法(至少在C ++ 03中是)將立即索引集作為數組傳遞。

我已經在G ++ 4.5.1(Windows / MinGW)上進行了檢查,並確認在-O3上進行了調用:

s[1][2][3][4];

產生與以下代碼相同的匯編代碼:

s(1,2,3,4);

因此-如果您的編譯器很聰明且具有優化功能,則不會產生運行時開銷。 干得好,GCC團隊!

代碼如下:

#include <iostream>

template<typename T, unsigned N, unsigned Count>
struct PartialResult
{
    static const int IndicesRemembered = Count-1-N;
    T& t;
    int args[IndicesRemembered];
    PartialResult(T& t, int arg, const int* rest) : t(t) {
        for (int i=0; i<IndicesRemembered-1; ++i) {
            args[i] = rest[i];
        }
        if (IndicesRemembered>0) args[IndicesRemembered-1] = arg;
    }
    PartialResult<T, N-1, Count> operator[](int k) {
        return PartialResult<T, N-1, Count>(t, k, args);
    }
};

template<typename T, unsigned Count>
struct PartialResult<T, 0, Count>
{
    static const int IndicesRemembered = Count-1;
    T& t;
    int args[IndicesRemembered];
    PartialResult(T& t, int arg, const int* rest) : t(t) {
        for (int i=0; i<IndicesRemembered-1; ++i) {
            args[i] = rest[i];
        }
        if (IndicesRemembered>0) args[IndicesRemembered-1] = arg;
    }
    void operator[](int k) {
        int args2[Count];
        for (int i=0; i<Count-1; ++i) {
            args2[i] = args[i];
        }
        args2[Count-1] = k;
        t(args2);
    }
};

template<typename T, unsigned Count>
struct InitialPartialResult : public PartialResult<T, Count-2, Count> {
    InitialPartialResult(T& t, int arg)
        : PartialResult<T, Count-2, Count>(t, arg, 0) {}
};

struct C {

    void operator()(const int (&args)[4]) {
        return operator()(args[0], args[1], args[2], args[3]);
    }
    void operator()(int a, int b, int c, int d) {
       std::cout << a << " " << b << " " << c << " " << d << std::endl;
    }
    InitialPartialResult<C, 4> operator[](int m) {
        return InitialPartialResult<C, 4>(*this, m);
    }

};

嚴重的是,請不要使用它,而要堅持使用operator() :)干杯!

我會完全避免這種情況,只提供operator() ,但是如果您真的想試一試,則想法是您類型的operator[]將返回一個同時具有對您的對象和對象的引用的輔助類型的對象。傳入的值。該幫助程序類將通過再次存儲對原始對象的引用以及對[]兩次調用的參數來實現operator[] [] 除最后一個級別(即大量的助手)外,所有其他人都必須這樣做。 在最后一級, operator[]將其參數與所有先前存儲的值一起使用,並與所有先前存儲的值加當前值一起調用operator()

短語的一種常用說法是,每個中間類型都將對operator()的調用的參數之一綁定 ,而最后一個對所有綁定的參數執行該調用。

根據是否要支持更多或更少數量的數組維數,您可能希望/需要使其復雜化以使其通用。 通常,不值得付出努力,僅提供operator()通常是解決方案。 請記住,最好使事情盡可能簡單:減少編寫工作的精力,而減少維護工作的精力。

這是對bind方法的嘗試。 我懷疑它是否特別有效,並且其中包含一些令人討厭的內容,但如果有人知道如何修復它,我會發布它。 請編輯:

template <int N>
struct Helper {
    function_type<N>::type f;
    explicit Helper(function_type<N>::type f) : f(f) {}
    Helper<N-1> operator[](int p) {
        return Helper<N-1>(bound<N-1>(f,p));
    }
};

template<>
struct Helper<0> {
    function_type<0>::type f;
    explicit Helper(function_type<0>::type f) : f(f) {}
    operator int() {
        return f();
    }
};

Helper<3> S::operator[](int p) {
    return Helper<3>(std::bind(s, _1, _2, _3));
}

其中s是一個表達式,該表達式返回綁定到this operator() std::bind(std::mem_fun(S::operator(), this, _1, _2, _3, _4)) 盡管我不記得std::bind是否已經可以處理成員函數,但可能不需要mem_fun

function_type<N>::typestd::function<int, [int, ... n times]>bound<N>function_type<N>::type bound(function_type<N+1>::type f, int p) { return std::bind(f, p, _1, _2, ... _N); } function_type<N>::type bound(function_type<N+1>::type f, int p) { return std::bind(f, p, _1, _2, ... _N); } 我不確定如何遞歸地定義它們,但是您可以列出它們的上限。

這是一個Fusion實現,支持任意參數和返回類型。 對任何可以使用此功能的人都表示感謝(如果可以,請告訴我)!

template <class Derived, class ReturnValue, class Sequence>
struct Bracketeer
{
    typedef ReturnValue result_type;
    typedef boost::fusion::result_of::size<Sequence> Size;

    struct RvBase
    {
        Sequence sequence;
        Derived *derived;
    };

    template <int n>
    struct Rv : RvBase
    {
        Rv(Derived *d) { this->derived = d; }
        Rv(RvBase *p) : RvBase(*p) { }
        Rv<n-1> operator[](typename boost::fusion::result_of::at_c<Sequence const, n-1>::type v)
        {
            boost::fusion::at_c<Size::value - 1 - n>(sequence) = v;
            return Rv<n-1>(this);
        }
    };

    template <>
    struct Rv<0> : RvBase
    {
        Rv(Derived *d) { this->derived = d; }
        Rv(RvBase *p) : RvBase(*p) { }
        ReturnValue operator[](typename boost::fusion::result_of::at_c<Sequence, Size::value - 1>::type v)
        {
            boost::fusion::at_c<Size::value - 1>(sequence) = v;
            return invoke(*derived, sequence);
        }
    };

    Rv<Size::value - 1> operator[](typename boost::fusion::result_of::at_c<Sequence, 0>::type v)
    {
        Rv<Size::value> rv(static_cast<Derived*>(this));
        return rv[v];
    }
};

struct S
    :
    Bracketeer<S, int, boost::fusion::vector<int, int, int, int> >
{
    int operator()(int a, int b, int c, int d);
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM