簡體   English   中英

C / C ++中的句法糖

[英]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 ++中使用的類似技巧的參考文獻,那將是很棒的。

誰能提出更好的選擇?

是。 根本不要這樣做。 只需直接使用whileif語句即可。

當您使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM