我一直在研究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 ++中使用的类似技巧的参考文献,那将会很棒。
答案 0 :(得分:109)
有人可以提出更好的选择吗?
是。根本不要这样做。只需直接使用while
和if
语句。
当您使用C或C ++编程时,请使用C或C ++编程。虽然until
和unless
可能在某些语言中经常使用和惯用,但它们不是C或C ++。
答案 1 :(得分:16)
你做的方式在我看来是正确的方法,如果你要去做的话。因为宏的扩展所以类似于你期望的[1],我认为使宏看起来像syntax()是有效的,而不是通常推荐的SCARY_UPPERCASE_MACROS()用于表明此代码不遵循通常的语法,您应该只使用它。
[1]唯一的缺陷是无法声明变量,无论如何都不太可能,并且如果使用不当可能会在正确的位置产生错误,而不是做一些奇怪的事情。
此外,即使可读性的小幅提升也很重要,因此能够说until (
而不是while (!
确实能够更容易地阅读许多循环。如果结束条件更容易被认为是一种异常条件(无论是否存在),那么以循环方式编写循环会使其更容易阅读。所以即使它只是语法糖,我认为有理由考虑它。
然而我不认为这是值得的。好处很小,因为大多数程序员习惯于阅读if (!
并且成本是真实的:阅读代码的任何人都必须检查这是一个宏,还是一个自定义编译器,以及它是否符合他们的想法。它可能误导你认为你可以做i=5 unless xxxx;
之类的事情。这种微小的改进,如果普遍存在,会破坏语言,所以通常最好以标准方式做事,并慢慢采取改进措施。
然而,它可以做得很好:整个boost和tr1,特别是使用模板看起来像库的扩展的东西,涉及以各种方式扩展C ++,其中许多不被采用,因为他们没有'看起来很值得,但其中许多都有小的或非常广泛的吸收,因为他们做了真正的改进。
答案 2 :(得分:13)
这让我想起了我在某人的代码中看到的东西:
#define R return;
此外,使代码难以理解,会增加维护成本。
答案 3 :(得分:8)
我建议最好不要使用它们。
您不能将它们用作Ruby样式
`printf("hello,world") unless(a>0);`
是非法的。
C程序员更难理解代码。同时额外的宏可能是一个问题。
答案 4 :(得分:5)
如果要定义宏,最好让它们看起来很难看。特别是,它们应该是全部大写,并且具有某种前缀。这是因为没有命名空间,也没有与类型系统或C ++重载解析的协调。
因此,如果您的宏被称为BIGYAN_UNNECESSARY_MACRO_UNTIL
,那么它将不会“超越苍白”。
如果你想用新的循环结构扩展C ++,可以考虑调查C ++ 0x中的lambdas,你可以允许:
until([&] { return finished; }, [&]
{
// do stuff
});
它并不完美,但它比宏更好。
答案 5 :(得分:5)
我不认为你的宏特别糟糕,如果它们只用于 你自己的代码库。 This article 可能对你有意思。 话虽这么说,但是当我们在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
子句。
答案 6 :(得分:2)
看看如何加强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;
答案 7 :(得分:2)
良好的语法糖示例(恕我直言):
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
答案 8 :(得分:1)
正如人们所说,添加这些词实际上并不能提供有用的语法糖,因为读取一段时间的成本(或者if(!很小,所有C开发人员都习惯了,使用这样的宏你会吓人的)大多数C开发人员。另外,让一种语言看起来像另一种语言并不是一个好主意。
但是,语法糖很重要。如前所述,在C ++中,boost通过模板添加很多语法糖,而stl也提供Somme糖(例如,std::make_pair(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 ++更灵活,允许创建运算符(例如&amp; ^,+。,:+:,...),所以我们可以想象有人会快速介绍语法糖再次:)。
答案 9 :(得分:-1)
您可以这样做,但是请确保它不在源文件中。我建议在不生成优化的情况下将CoffeeScript方法用于JavaScript。
通常,您应该编写语言,但是导出,给出和拥有已转译的代码,就像您将以极好的兼容性用C编写它一样。
尝试查看awk
,并使其在保存时或类似的情况下以所有结尾为.cugar
的文件的形式进行编译。 :)
祝你好运。