C/C++中的句法糖

BiG*_*YaN 31 c c++ syntax metaprogramming syntactic-sugar

我一直在研究Ruby并发现它的关键字"直到"和"除非"非常有趣.所以我认为在C/C++中添加类似关键字的好方法是什么.这就是我想出的:

#define until(x)    while(!(x))
#define unless(x)   if(!(x))
Run Code Online (Sandbox Code Playgroud)

我正在寻找一些建议.谁能提出更好的选择?

这是我编写的一个程序示例,用于说明我打算做什么:

#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;
}
Run Code Online (Sandbox Code Playgroud)

如果你能指出一些可以在C或C++中使用的类似技巧的参考文献,那将是很棒的.

Jam*_*lis 108

谁能提出更好的选择?

是.根本不要这样做.只需直接使用whileif语句.

当您使用C或C++编程时,请使用C或C++编程.虽然until并且unless可能在某些语言中经常使用和惯用,但它们不是C或C++.

  • +1就此而言.在Ruby中执行此操作可能是惯用的,但是你不是用Ruby编程的吗?不要试图强迫一种语言像另一种语言一样,你只是想用这种方式编写错误的代码. (15认同)
  • @BiGYaN:最好的办法就是不要这样做. (15认同)
  • 我知道在这样的大环境中,这样编码只会带来麻烦.但我的问题是这样做的最佳方式是什么; 而不是关于是否这样做. (6认同)

Jac*_* V. 16

你做的方式在我看来是正确的方法,如果你要去做的话.因为宏的扩展与你期望的那样相似[1],我认为使宏看起来像syntax()是有效的,而不是通常推荐的SCARY_UPPERCASE_MACROS()用来表明这段代码没有不遵循通常的语法,你应该只仔细使用它.

[1]唯一的缺陷是无法声明变量,无论如何都不太可能,并且如果使用不当可能会在正确的位置产生错误,而不是做一些奇怪的事情.

此外,即使可读性的小幅增加也很重要,因此能够说until (而不是while (!真的能够更容易地阅读许多循环.如果结束条件更容易被认为是一种异常条件(无论是否存在),那么以循环方式编写循环会使其更容易阅读.所以即使它只是语法糖,我认为有理由考虑它.

但是我不认为这是值得的.好处很小,因为大多数程序员习惯于阅读if (!并且成本是真实的:阅读代码的任何人都必须检查这是一个宏,还是自定义编译器,以及它是否符合他们的想法.它可能误导你认为你可以做的事情i=5 unless xxxx;.这种微小的改进,如果广泛使用,会破坏语言,因此通常最好以标准方式做事,并慢慢采取改进措施.

但是,它可以做得很好:整个boost和tr1,特别是使用模板看起来像库的扩展的东西,涉及以各种方式扩展C++,其中许多不被采用,因为它们似乎不值得它,但其中很多都有小的或非常广泛的吸收,因为它们做了真正的改进.

  • 至少可以说,这个答案的第一段是有问题的!宏不是命名空间; 他们完全是全球性的.因此,给他们提供可能在其他地方使用的短名称是非常糟糕的.如果您定义一个具有短名称的宏,例如`until`,然后您包含一个声明成员函数`until`的第三方标题,那么该标题将被破坏.它会尝试声明`void until(int a);`而是会说`void while(!(int a));`祝你好运解密那条错误信息!所以(不出所料)Boost使用可怕的大写名称和所有宏技巧的前缀. (4认同)

BЈо*_*вић 13

这让我想起了我在某人的代码中看到过的东西:

#define R return;
Run Code Online (Sandbox Code Playgroud)

此外,使代码难以理解,会增加维护成本.

  • @smallstrings OMG (3认同)

xis*_*xis 8

我建议最好不要使用它们.

你不能在Ruby风格中使用它们

`printf("hello,world") unless(a>0);`
Run Code Online (Sandbox Code Playgroud)

是非法的.

而且C程序员更难理解代码.同时额外的宏可能是一个问题.

  • a> 0 && printf("Hello,world!"); ? (6认同)

Dan*_*ker 5

如果您要定义宏,那么让它们看起来非常丑陋是一种很好的做法.特别是,它们应该是全部大写,并且具有某种前缀.这是因为没有命名空间,也没有与类型系统或C++重载解析的协调.

因此,如果您的宏被调用,BIGYAN_UNNECESSARY_MACRO_UNTIL那么它将不会"超越苍白".

如果你想用新的循环结构扩展C++,可以考虑在C++ 0x中调查lambdas,你可以允许:

until([&] { return finished; }, [&] 
{
    // do stuff
});
Run Code Online (Sandbox Code Playgroud)

它并不完美,但它比宏更好.

  • 你为此提议使用lambdas会让我今晚做恶梦 (2认同)
  • 对于像重新实现`while(!b)`那样简单的事情,它显然有点过分. (2认同)

Ise*_*ria 5

如果它们仅在您自己的代码库中使用,我认为您的宏不是特别糟糕. 这篇文章 可能对你有意思.话虽这么说,当我们在C++中使用它们时,我会看到你的宏的一些缺点.
例如,我们不能写为:

until (T* p = f(x)) ...
unless (T* p = f(x)) ...
Run Code Online (Sandbox Code Playgroud)

另一方面,我们可以写为:

while (T* p = f(x)) ...
if (T* p = f(x)) ...
Run Code Online (Sandbox Code Playgroud)

至于unless,如果我们将其定义为:

#define unless(x) if (x) {} else
Run Code Online (Sandbox Code Playgroud)

那我们就可以写了unless (T* p = f(x)) ....但是,在这种情况下我们不能else在它之后添加子句.