2016-09-15 138 views
15

考慮以下結構(?):空隙(),逗號運算符(操作員)和不可能超載

struct S {}; 

在C++ 14中,定義以下是有效的:

constexpr auto f() { return S{}, 'c'; } 

除了下列之一:

constexpr auto f() { return S{}, void(); } 

現在,考慮到涉及第一兩種定義的下面,工作片斷:

#include<type_traits> 

struct S {}; 

constexpr int operator,(S, char) { return 42; } 
constexpr auto f() { return S{}, 'c'; } 

int main() { 
    constexpr int i{f()}; 
    static_assert(i == 42, "!"); 
    static_assert(std::is_same<decltype(f()), int>::value, "!"); 
} 

說起不那麼技術上,逗號運算攔截夫婦S{}, 'c'並返回一個整數的過載,如main功能正確驗證。

現在,假設我希望做同樣與f第二個定義:

constexpr auto f() { return S{}, void(); } 

在這種情況下,逗號操作符應該攔截形式S{}, void()
無論如下定義作品(原因很明顯):

constexpr int operator,(S, void) { return 42; } 

也不下一個(這將在前面的情況下工作過):

template<typename T> constexpr int operator,(S, T &&) { return 42; } 

有什麼辦法重載逗號運營商如何處理S{}, void()
是不是它在標準中缺乏,因爲它允許以這種方式使用逗號運算符,但不會給您重載相同運算符的機會(即使the standard mentions that overloaded functions involving S are allowed)?


注意:這個問題對我的好奇心起見。請避免像這樣的意見不要那樣做這是不好的做法。我不打算在生產環境中這樣做。謝謝。

+2

這很吸引人瘋狂;) –

+0

@JesperJuhl是的,我知道。標準游擊隊員。我正在探索語言中最隱蔽的角落。 :-) – skypjack

+0

將運算符','改成'+'給出一個「參數可能沒有'void'type」錯誤。 – kennytm

回答

20

此相關的條款是13.3.1.2/9 [over.match.oper]在N4140:

如果操作者是操作,,一元運算符&,或者操作員->,並且沒有可行函數, 則操作被假定爲內置的操作者和解釋根據條款5.

void()作爲從來都不是一個有效的函數的參數(見5.2.2/7 [EXPR .call]),那裏ne ver是一個可行的功能,因此將使用內置的,

所以不,你想要做的是不可能的。

其實,寫一個迭代循環這樣

for(...; ++it1, (void)++it2) 

是通過執行內置運營商,使用重載,他們的迭代器類型,以防止用戶破壞你的代碼的標準方式。 (請注意,我不是說你需要做這在日常的代碼這在很大程度上取決於它的實際使用這是偏執的標準庫的水平。)


關於你所連接的標準條款:

運營商=所述的含義,(一元)&,和,(逗號),預定義的每種類型,可以通過定義實現這些運算符操作員功能更改爲特定類和枚舉類型

但是這樣的函數不能被定義,因爲如上所述,void()永遠不是有效的函數參數。

現在,無論這是否是標準中的疏忽/問題,都有待討論。

+2

在循環中有趣地使用'(void)'來避免調用重載的逗號。謝謝你的提示! – paulotorrens