2011-11-25 22 views
1

對於某些模板類型名,我想創建一個typedef,它是T :: operator ++()(又名T的預增加運算符)的聲明返回類型。使用重載運算符++的C++ decltype ++(preincrement)

我沒有找到任何明確的在線,但肯定有一些decltype提前preincrement提到。所以我嘗試了一些東西,而唯一真正起作用的東西似乎是一個骯髒的黑客。你覺得這怎麼樣?

struct S { // dummy type to simulate a real one I have 
    int operator++() { return 0; } // note: return type is not S& 
    int operator++(int) { return 0; } 
}; 

int main() { 
    // this works: 
    typedef decltype(++S()) T1; 

    // so why doesn't this work? 
    // error: lvalue required as increment operand 
    // typedef decltype(++int()) T2; 

    // this works, but seems dirty: 
    typedef decltype(++*(int*)nullptr) T3; 
    typedef decltype(++*(S*)nullptr) T4; 

    // I also haven't figured out how to disambiguate this, 
    // though it's moot because int::operator++ is not a thing 
    // error: ‘S::operator++’ refers to a set of overloaded functions 
    // typedef decltype(S::operator++) T5; 
} 

我正在使用GCC 4.6.2。我簡單地嘗試過Clang,但它並不好。

+1

FWIW,你不能用'decltype'做一個''++表達式用於獲取*申報*返回類型 - 它曾經用於一些C++ 11草案,但是發佈的規範不再使用這個工作。所以如果你聲明返回類型爲int const,那麼'decltype'會給你的是'int'而不是'int const'。雖然除了這個人爲的例子,我並沒有意識到獲取*聲明*返回類型和簡單表達式類型(發佈的規範產生的)之間的真正區別。 –

+0

我可以忍受這一點。謝謝你的明確解釋。 –

回答

1

內置和用戶定義類型的不同lvalueness在臨時對象的情況下:在你的例子的臨時 int是一個rvalue,但臨時 S是一個左值。

編輯:從技術上講,所有臨時值都是右值,但操作符與用戶定義類型的工作方式不同,因爲它們實際上是僞裝的常規函數​​。這意味着你可以用它們做一些非rvalue類似的事情,比如將S()作爲默認賦值運算符的左邊!

使用declval獲得在非計算上下文中的任意類型的左值或右值:

#include <utility> 

// declval<T&> yields an lvalue, declval<T> an rvalue 
typedef decltype(std::declval<int&>()++) T1; // int 
typedef decltype(++std::declval<int&>()) T2; // int& 

typedef decltype(std::declval<S&>()++) T3; // S 
typedef decltype(++std::declval<S&>()) T4; // S& 
+0

這很有趣,但在我關心的所有平臺上都不支持declval(例如Boost 1.45和GCC 4.4)。我可以通過複製/粘貼Boost的內容來自己製作,但是它會相當長和醜,而不是IMO比decltype(++ *(S *)nullptr)更好。 –

+0

@JohnZwinck把'*(S *)nullptr'放入一個函數並調用'declval'肯定會更好。我不知道最近Boost做了什麼(例如解決方法),但這基本上就是它應該是的。 – Potatoswatter

+0

-1:'S()'不是左值。 –