[英]Syntactic sugar in C/C++
我一直在研究Ruby並發現它的關鍵字“直到”和“除非”非常有趣。 所以我認為在C / C ++中添加類似關鍵字的好方法是什么。 這就是我想出的:
#define until(x) while(!(x))
#define unless(x) if(!(x))
我正在尋找一些建議。 誰能提出更好的選擇?
這是我編寫的一個程序示例,用於說明我打算做什么:
#include <stdio.h>
#include <stdlib.h>
#define until(x) while(!(x))
#define unless(x) if(!(x))
unsigned int factorial(unsigned int n) {
unsigned int fact=1, i;
until ( n==0 )
fact *= n--;
return fact;
}
int main(int argc, char*argv[]) {
unless (argc==2)
puts("Usage: fact <num>");
else {
int n = atoi(argv[1]);
if (n<0)
puts("please give +ve number");
else
printf("factorial(%u) = %u\n",n,factorial(n));
}
return 0;
}
如果你能指出一些可以在C或C ++中使用的類似技巧的參考文獻,那將是很棒的。
誰能提出更好的選擇?
是。 根本不要這樣做。 只需直接使用while
和if
語句即可。
當您使用C或C ++編程時,請使用C或C ++編程。 雖然until
並且unless
可能會經常和習慣在一些語言中使用的,他們不是在C或C ++。
你做的方式在我看來是正確的方法,如果你要去做的話。 因為宏的擴展與你期望的那樣相似[1],我認為使宏看起來像syntax()是有效的,而不是通常推薦的SCARY_UPPERCASE_MACROS()用來表明這段代碼沒有不遵循通常的語法,你應該只仔細使用它。
[1]唯一的缺陷是無法聲明變量,無論如何都不太可能,並且如果使用不當可能會在正確的位置產生錯誤,而不是做一些奇怪的事情。
此外,即使是可讀性的小幅增加也很重要,因此可以說until (
而不是while (!
確實讓它更容易閱讀許多循環。如果結束條件更容易被認為是一種例外情況(無論是否是或不)以循環方式編寫循環使其更容易閱讀。所以即使它只是語法糖,我認為有理由考慮它。
但是我不認為這是值得的。 好處很小,因為大多數程序員習慣於閱讀if (!
並且成本是真實的:閱讀代碼的任何人都必須檢查這是一個宏,還是自定義編譯器,以及它是否符合他們的想法。它可能誤導你會認為你可以做像i=5 unless xxxx;
這樣的事情, i=5 unless xxxx;
這些小改進,如果普遍存在,會破壞語言,所以通常最好以標准方式做事,並慢慢采取改進措施。
但是,它可以做得很好:整個boost和tr1,特別是使用模板看起來像庫的擴展的東西,涉及以各種方式擴展C ++,其中許多不被采用,因為它們似乎不值得它,但其中很多都有小的或非常廣泛的吸收,因為他們做了真正的改進。
這讓我想起了我在某人的代碼中看到過的東西:
#define R return;
此外,使代碼難以理解,會增加維護成本。
我建議最好不要使用它們。
你不能在Ruby風格中使用它們
`printf("hello,world") unless(a>0);`
是非法的。
而且C程序員更難理解代碼。 同時額外的宏可能是一個問題。
如果您要定義宏,那么讓它們看起來非常丑陋是一種很好的做法。 特別是,它們應該是全部大寫,並且具有某種前綴。 這是因為沒有命名空間,也沒有與類型系統或C ++重載解析的協調。
因此,如果您的宏被稱為BIGYAN_UNNECESSARY_MACRO_UNTIL
那么它將不會“超越蒼白”。
如果你想用新的循環結構擴展C ++,可以考慮在C ++ 0x中調查lambdas,你可以允許:
until([&] { return finished; }, [&]
{
// do stuff
});
它並不完美,但它比宏更好。
如果它們僅在您自己的代碼庫中使用,我認為您的宏不是特別糟糕。 這篇文章可能對你有意思。 話雖這么說,當我們在C ++中使用它們時,我會看到你的宏的一些缺點。
例如,我們不能寫為:
until (T* p = f(x)) ...
unless (T* p = f(x)) ...
另一方面,我們可以寫為:
while (T* p = f(x)) ...
if (T* p = f(x)) ...
至於unless
,如果我們將其定義為:
#define unless(x) if (x) {} else
然后我們可以寫unless (T* p = f(x)) ...
但是,在這種情況下,我們不能在它之后添加else
子句。
好的語法糖例子(恕我直言):
struct Foo {
void bar() {}
};
typedef std::vector<Foo*> FooVector;
typedef boost::ptr_vector<Foo> FooPtrVector;
FooVector v1;
for (FooVector::iterator it = v1.begin(); it != v1.end(); ++it)
(*it)->bar(); // ugly
FooPtrVector v2;
for (FooPtrVector::iterator it = v2.begin(); it != v2.end(); ++it)
it->bar(); // nice
看看如何提升foreach。
標頭定義了BOOST_FOREACH(丑陋的前綴宏)。 您可以
#define foreach BOOST_FOREACH
在.cpp文件中,以便有更清晰的代碼。 你不應該在你的.h文件中這樣做,而是使用丑陋的BOOST_FOREACH。
現在,這里有一組用於“方便”IF THEN ELSE表達式的“functional-programming-ish”宏(因為?:很難看):
#define IF(x) (x) ?
#define ELSE :
現在
int x = IF(y==0) 1
ELSE IF(y<0) 2*y
ELSE 3*y;
desugarises into:
int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;
正如人們所說的那樣,添加這些詞實際上並沒有提供有用的語法糖,因為讀取一段時間的成本(或者if(!很小,所有C開發人員都習慣了,並且使用這樣的宏,你會嚇到大部分的C開發人員。另外,使語言看起來像另一個並不是一個好主意。
但是,語法糖很重要。 如前所述,在C ++中,boost通過模板添加很多語法糖,而stl也提供Somme糖(例如, std::make_pair(a, b)
是std::pair<decltype(a), decltype(b)>(a, b)
的語法糖std::pair<decltype(a), decltype(b)>(a, b)
。
隨着語言的改進,添加了功能和語法糖,以提高開發人員的可讀性,可寫性和效率。 例如,使用C ++ 11規范,添加了“for(數據結構中的元素)”(見下文),以及允許對類型進行一周推斷的“auto”關鍵字(我說弱,因為你需要輸入許多類型的類型實際上是“明顯的”和冗余的很多類型。
另外,在haskell中,使用不帶符號的單子(語法糖)將是一個真正的痛苦,沒有人會使用它們1 。
沒有句法糖的例子:
//C++ < 11
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(9);
v.push_back(12);
for (std::vector<int>::iterator it = v.begin();
it != v.end();
it++)
{
std::cout << *it << std::endl;
}
用語法糖:
//C++ >= 11
std::vector<int> v {3, 7, 9, 12};
for (auto elm : v)
{
std::cout << elm << std::endl;
}
有點可讀,不是嗎?
IO monad的一個haskell示例(來自HaskellWiki ):
f :: IO String
f =
ask "What's your name ?" >>= \name ->
putStrLn "Write something." >>= \_ ->
getLine >>= \string ->
putStrLn ("Hello " ++ name ++ " you wrote " ++ string) >>= \_ ->
return name
g :: IO String
g = do
name <- ask "What's your name ?"
putStrLn "Write something."
string <- getLine
putStrLn ("Hello " ++ name ++ " you wrote " ++ string)
return name
以下是ideone的鏈接: http ://ideone.com/v9BqiZ
1 :實際上,語言比C ++更靈活,允許創建運算符(例如&^,+。,:+:,...),所以我們可以想象有人會很快再次引入語法糖:)。
那么你可以做到,但要確保它不在源文件中。 我建議在沒有優化生成的情況下將CoffeeScript方法應用於JavaScript。
一般來說,你應該編寫你的語言,但是導出,給出和編譯轉換后的代碼就好像你用C語言編寫它具有極高的兼容性。
嘗試查看awk
並使其轉換所有文件,結尾.cugar
保存或類似的東西。 :)
祝好運。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.