2014-11-22 56 views
2

有沒有一種方法來定義可以從'const'&'非const'對象訪問的成員函數?通用成員函數定義,可從'const'和'non-const'對象實例化

我需要這個爲我的sList實現列表類。在這個函數中,我想聲明一個函數,該函數將'const'或'non-const'指針作爲參數的另一個函數指向sList,並將其稱爲當前sList結構中的每個列表。

這裏是它的聲明:

template <typename T> 
struct sList 
{ 
    sList(initializer_list<T>); 

    inline void DoForEachList(auto pFunc) 
    { 
     for(auto p = this; p; p = p->pNext) 
      pFunc(p); 
    } 

    ~sList(); 

    T dat; 

    sList *pNext = nullptr; 
}; 

我使用auto pFunc因爲我想最終lambda表達式通得過。所以,現在如果我有一個這種類型的const對象,並從它的'DoForEachList'作爲參數lambda函數進行調用,並且類型爲'auto'的1個參數。我的編譯器將失敗的東西,如:

error: passing const sList<unsigned char> as this argument of void sList<T>::DoForEachList(auto:1) [with auto:1 = main()::<lambda(sList<unsigned char>*)> ; T = unsigned char ]' discards qualifiers [-fpermissive]

和代碼調用DoForEachList

void main() 
{ 
    extern const sList<unsigned char> cvobj; 
    cvobj.DoForEachList([] (auto pCurr) {/* Do something */}); 
} 

有一些方法可以讓我定義DoForEachList成員函數(或成員函數模板)是這樣的:

template <typename T> 
struct sList 
{ 
    inline void DoForEachList(auto pFunc) auto //either 'const' or none 
    { 
     for(auto p = this; p; p = pNext->pNext) 
      pFunc(p); 
    } 

    //... 
}; 
+2

您可以使用朋友函數模板,也可以使用兩個成員函數包裝器。 – dyp 2014-11-22 22:04:27

+0

非常簡單 - 一個非const對象總是可以綁定到一個'const'引用,但不是相反。這是一個隱式轉換(合格轉換)。嗯。如果你真的想修改對象,但是如果你在一個非const對象上調用它,那就沒用了。在這種情況下,只需編寫兩個函數。 – Deduplicator 2014-11-22 22:06:15

+0

身體一樣 - 呃,這是最好的方法嗎?使用包裝函數不是一個解決方案,因爲那麼'pFunc'參數會被錯誤地推導出來(如果我們在'const'成員函數中使用const_cast'this'包裝'非const'調用,那麼lambda函數arg將被推斷爲' sList *'這是錯誤的)。 – AnArrayOfFunctions 2014-11-22 22:26:31

回答

6

要通過@dyp在評論建立在答案:

如果您想要在this的常量上超載,則確實需要兩個單獨的函數。但是,您可以通過將工作卸載到輔助函數來最大限度地減少重複工作。

@dyp建議使用朋友函數模板來做這個,但朋友函數沒有訪問控制,所以我通常更喜歡靜態成員函數;然後你可以把它私有或保護:

template <typename T> 
struct sList 
{ 
    void DoForEachList(auto pFunc) 
    { 
     DoForEachListHelper(*this, pFunc); 
    } 
    void DoForEachList(auto pFunc) const 
    { 
     DoForEachListHelper(*this, pFunc); 
    } 
private: 
    static void DoForEachListHelper(auto&& self, auto pFunc) 
    { 
     for(auto p = &self; p; p = pNext->pNext) 
      pFunc(p); 
    } 
}; 
+0

@ hvd謝謝。有了'auto &&',你也可以在ref修飾符上重載'DoForEachList',而不是在這種情況下有很大的區別。 – Oktalist 2014-11-22 23:02:13

+0

是的,當我注意到它可能是'auto self'時,那是我第一次提出'self'是指針的提示,在這種情況下'&&'根本沒有用處。在這種特殊情況下,'self'是一個參考,它仍然沒有什麼區別,因爲你只是用左值來調用它,但這是一個簡單而有用的一般方法,我可以看出爲什麼選擇它。 :) – hvd 2014-11-22 23:10:17

+0

*「朋友功能沒有訪問控制。」*我不明白你在這裏說什麼。 – dyp 2014-11-22 23:17:39

0

你應該只使用const成員函數,使成員變量mutable,它告訴編譯器/你該成員不影響「過氣,改變「這個班的行爲。如果情況並非如此,請重新考慮您的設計,因爲這不太正確。 mutable更準確,例如,地圖的關鍵需求,在這樣的,它並沒有在地圖上影響排序的方式進行修改,但即使是這樣......

代碼示例:

struct Bla 
{ 
    void increment() const { i++; } 
private: 
    mutable int i = 0; 
}; 

int main() 
{ 
    const Bla bla; 
    bla.increment(); 
} 

Live demo here