繁体   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