2011-11-21 32 views
8

我最近(只在實際上)碰到了C/C++逗號運算符的用法。從我所知道的情況來看,它會在左側和右側操作符之間的界限上創建一個序列點,以便您可以預測(定義)評估順序。使用逗號運算符是不錯的做法嗎?

我對於爲什麼會在語言中提供這一點感到有點困惑,因爲它看起來像一個補丁,可以應用於不應該在第一個地方工作的代碼。我發現很難想象它可以被使用的地方不是太複雜(並且需要重構)。

有人可以解釋這種語言功能的用途和它可能用於真實代碼(在合理範圍內),如果有的話?

+0

這是一個聰明的用法:http://stackoverflow.com/questions/7905905/howto-check-a-type-for-the-existance-of-parameterless-operator/7906060#7906060 –

+4

@ R.MartinhoFernandes:聰明?我認爲你錯過了大局。在「高級」C++元編程中,沒有任何聰明的東西,只是受虐待。 – 6502

回答

11

它可以在while()循環的病症:

while (update_thing(&foo), foo != 0) { 
    /* ... */ 
} 

這避免了重複update_thing()線,同時還保持退出條件在while()控制表達式中,您期望找到它。它也與continue;很好地搭配。

它在編寫評估爲值的複雜宏時也很有用。

+0

謝謝大家:)這很有趣,我之前沒有想過在循環中實際使用過它,但直到我提出這個問題時才從未想到它是一個操作符。 (我知道,這是顯而易見的,所以我覺得有點傻!:p) –

8

逗號運算符只是分隔表達式,因此您可以執行多個事情而不是隻需要一個表達式的事情。它可以讓你做的事情一樣

   (x)    (y) 
for (int i = 0, j = 0; ...; ++i, ++j) 

注意x不是逗號運算符,但y是。

你真的不必考慮它。它有一些更神祕的用途,但我不相信它們是絕對必要的,所以它們只是好奇心。

1

我想唯一的常見的例子是用於循環:

for (int i = 0, j = 3; i < 10 ; ++i, ++j) 

正如c-faq提到:

在一段時間後,你會發現自己在一個情況,即C期望的一個 單一表達,但你有兩件事情要說。最常用的 (實際上唯一常見的)例子是for循環, 具體是第一個和第三個控制表達式。

+1

在第一部分(在你的例子中)它不是一個逗號運算符。 – 6502

+0

@ 6502 - 我需要'j' :) – MByD

+2

@MByD:這是一個逗號,但它沒有使用逗號運算符。逗號允許聲明幾個變量。儘管如此,右側的部分是commma運算符。 –

1

唯一合理的使用我能想到的是在for構建

for (int count=0, bit=1; count<10; count=count+1, bit=bit<<1) 
{ 
    ... 
} 

,因爲它允許多個變量的增量的同時,仍保持for構建結構(易於閱讀和理解對於訓練有素的眼睛)。

在其他情況下,我同意這有點壞的黑客...

+0

'count = count + 1'? 'bit = bit << 1'? –

+0

@SethCarnegie:是的。原始版本是'count ++,bit << = 1',但我認爲這樣更具可讀性。 – 6502

2

大家都在說它經常用在for循環中,這是真的。但是,我發現它在for循環的條件語句中更有用。例如:

for (int x; x=get_x(), x!=sentinel;) 
{ 
    // use x 
} 

,改寫本沒有逗號操作將需要做的,我是不是完全滿意的幾件事情,例如當它的使用範圍,或特殊外殼外面聲明X至少一個先致電get_x()

我也在繪製可以將它與C++ 11 constexpr函數結合使用的方式,因爲我猜它們只能由單個語句組成。

+1

你可以寫'(x = get_x())!= sentinel',但我發現你的方法更清晰。 – lhf

1

for環結構中,它可以是有意義的。儘管在這種情況下我通常會發現他們更難閱讀。

這對於激怒你的同事和人們也非常方便。

bool guess() { 
    return true, false; 
} 
+4

變量聲明中的逗號*不是*使用逗號*運算符*,它會產生值。 – lhf

1

逗號運算符對於將序列放在不能插入代碼塊的地方很有用。正如指出的那樣,這在編寫緊湊和可讀的循環中很方便。此外,它在宏定義中很有用。以下宏將增加警告的數量,並且如果設置了布爾變量,也會顯示警告。

#define WARN if (++nwarnings, show_warnings) std::cerr 

使您可以寫信(例如1):

if (warning_condition) 
    WARN << "some warning message.\n"; 

逗號操作符實際上是一個可憐的男人的lambda函數。

+1

這個宏很可怕 – u0b34a0f6ae

+0

是的,它可能是@ kaizer.se,但我已經開始重視實用主義,宏完成了工作。 –

0

我也用逗號粘合起來,相關的操作:

void superclass::insert(item i) { 
    add(i), numInQ++, numLeft--; 
} 
+0

如果在你的例子中'''將被';'替代,它會有什麼不同嗎?它看起來略有不同(雖然略微有些不同),但在這種情況下,「粘合在一起」意味着什麼? – TobiMcNamobi

+0

這裏沒有什麼區別。但會在這裏:'while(1)++ i,++ j'。粘合在一起意味着將這些語句進行邏輯分組,以便清楚顯示這些操作緊密相關。 – perreal

0

打魔鬼代言人,這可能是合理的扭轉問題:

它是很好的做法,總是使用分號結束符?

幾點:

  • 更換最分號用逗號將立即使大多數C和C++代碼更清晰的結構,並會消除一些常見的錯誤。
  • 與功能性編程相比,這更多的是功能性編程。
  • Javascript的'自動分號插入'是其有爭議的語法特徵之一。

這種做法是否會增加「常見錯誤」是未知的,因爲沒有人這樣做。

但是,當然,如果你這樣做,你可能會惹惱你的同行程序員,併成爲SO上的賤民。

編輯:查看AndreyT's優秀2009回答Uses of C comma operator。並且Joel 2008也談論了C#/ C/C++中的兩個並行語法類別。

作爲一個簡單的例子,while (foo) a, b, c;的結構很明顯,但是while (foo) a; b; c;在沒有縮進或大括號或兩者的情況下會造成誤解。

編輯#2:作爲AndreyT狀態:

[該] C語言(以及C++)是歷史上的兩種完全不同的程序設計風格,其中的一個可以是指爲「語句的混合編程「和」表達式編程「。

但他斷言, 「在實踐中聲明編程產生更可讀的代碼」[強調]顯然是。在你看來,用他的例子,以下兩行中的哪一行更具可讀性?

a = rand(), ++a, b = rand(), c = a + b/2, d = a < c - 5 ? a : b; 
a = rand(); ++a; b = rand(); c = a + b/2; if (a < c - 5) d = a; else d = b; 

:他們是不可讀。它是空白區域,它爲Python提供了可讀性 - 歡樂!第一個更短。但分號版本確實有更多像素黑色空間綠色空間如果您有Hazeltine終端 - 這可能是真正的問題嗎?

+0

考慮相反的立場總是很有趣,但是我希望看到更多關於你的觀點的證據,因爲在大多數情況下,它們之間的語義差異和;是相當小的。除了(;;)a,b,c與(;;)a很不相同外, b; C; –

+0

@鮑威:我沒有任何證據,正如我在答案中承認的那樣。但是你的兩個例子都很好:第一個for(;;)a,b,c;'是清楚的,但第二個for(;;)a; b; c「在缺乏縮進或大括號或兩者都是誤導。 –

+0

既然「佔領華爾街」運動似乎正在消退,也許我們可以將注意力轉回到逗號的重要問題上? –

0

儘管在C++ 11被批准幾個月後發佈,但我在這裏看不到有關constexpr函數的任何答案。 This answer爲一個不完全相關的問題引用了關於逗號運算符及其在常量表達式中的用處的討論,其中特別提及了新的constexpr關鍵字。

雖然C++ 14並放寬一些限制上constexpr功能,它仍然是有用的注意,逗號操作符可以授予你預見的有序操作的constexpr函數中,如(從上述討論):

template<typename T> 
constexpr T my_array<T>::at(size_type n) 
{ 
    return (n < size() || throw "n too large"), (*this)[n]; 
} 

甚至是這樣的:

constexpr MyConstexprObject& operator+=(int value) 
{ 
    return (m_value += value), *this; 
} 

這是否是有用完全取決於執行,但這些都只是兩個如何逗號運營商可能在應用簡單的例子功能。