2012-01-15 42 views
13

C++ 03允許您將函數參數限定爲const,volatile和/或左值引用(&)。C++ 11:抽象const,volatile,左值引用和右值引用合格的成員函數指針?

C++ 11增加了一個:右值引用(&&)。此外,C++允許您基於參數的限定符重載函數,以便在調用函數時選擇最合適的重載。

成員函數在概念上可以被認爲是一個函數,它接受一個額外的參數,其類型是對其所屬類的實例的引用。基於這個「額外參數」限定符的成員函數可以像其他任何參數一樣重載。這是通過把在限定符函數簽名的端部表示爲:

struct Foo 
{ 
    int& data();    // return a non-const reference if `this` is non-const 
    const int& data() const; // return a const reference if `this` is const 
}; 

在C++ 03,constvolatile限定符是可能的,以及C++ 11還允許&&&&理論上可以有被允許在C++ 03中,但它不是)。

可以使用限定符的任意組合,但&&&是互斥的,這使C++ 03中的2^2 = 4個可能性和C++ 11中的2^4-4 = 12 。

這可以是一個相當痛苦,當你想使用成員函數指針的工作,因爲他們甚至沒有一點點的多態性在這些限定:在成員函數指針的「this類型」爲順利通過了預選賽參數必須與它傳遞的參數類型完全匹配。 C++也沒有提供明確的工具來抽象限定符。在C++ 03中,這大多是好的,因爲你必須編寫const版本和非const版本,沒有人關心volatile,但是在C++ 11的病態情況下(這並不罕見)是病態的),您可能必須手動編寫多達12個重載。每個功能。

我很高興地發現,如果你是通過封裝類作爲模板參數的類型,並能從中得到一個成員函數指針的類型,constvolatile預選賽被允許和傳播你所期望的:

template<typename Object> 
struct Bar 
{ 
    typedef int (Object::*Sig)(int); 
}; 

Bar<Baz>;    // Sig will be `int (Baz::*)(int)` 
Bar<const Baz>;   // Sig will be `int (Baz::*)(int) const` 
Bar<volatile Baz>;  // Sig will be `int (Baz::*)(int) volatile` 
Bar<const volatile Baz>; // Sig will be `int (Baz::*)(int) const volatile` 

這是一個很大的不必手動寫出所有的情況更好。

不幸的是,它似乎不適用於&&&

GCC 4.7說:

error: forming pointer to reference type ‘Baz&&’

但是,這不是太奇怪,因爲作爲GCC 4.7還沒有對this參考預選賽支持。

error: member pointer refers into non-class type 'Baz &&'

呵呵,好了:

我也鐺3.0,它確實有這樣的支持試了一下。

我正確地斷定這是不可能的,並且沒有辦法在成員函數指針的「this type」上抽象引用限定符嗎?除了在通過「this類型」作爲模板參數時的特定情況之外,還可以使用任何其他用於限定符(尤其是this)抽象的技術。 (值得指出的是,如果C++沒有區分成員函數和普通函數,這將會很簡單:您將使用模板參數作爲函數(指針)的參數類型,並且模板參數將按原樣傳遞,修飾符完好無損,無需額外考慮。)

+1

對於所有可能的限定符組合,你需要多少次不同的行爲? (或者,對於這個問題,甚至有兩種或三種可能的組合) – 2012-01-15 19:49:16

+1

如果我想爲函數類對象編寫一個抽象(本質上是std :: function但不一樣),那麼完整性是一個設計目標。我無法真正推斷或估計(至於多頻繁),但我知道我以前遇到過它。 – glaebhoerl 2012-01-15 20:25:29

回答

4

您是否想過簡單地專門化您的模板?

您可以再補充兩個版本:

template <typename Object> 
struct Bar<Object&> { 
    typedef int (Object::*Sig)(int)&; 
}; 

template <typename Object> 
struct Bar<Object&&> { 
    typedef int (Object::*Sig)(int)&&; 
}; 

然後編譯器會適當地挑選合適的專業化(或退回到一般情況下)。

這可以節省您從const/volatile的事情,但確實意味着您需要編寫代碼3次。

+0

是的,'const'和'volatile'智能處理的事實意味着我只需要編寫三個版本而不是十二個,這很好。 – glaebhoerl 2012-01-15 20:23:02