33

Ruby を調べていると、「until」と「unless」というキーワードが非常に興味深いことがわかりました。そこで、同様のキーワードを 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++ で使用できる同様のトリックの参考文献をいくつか教えていただければ幸いです。

4

10 に答える 10

109

誰かがより良い代替案を提案できますか?

はい。これは絶対にしないでください。whileandifステートメントを直接使用するだけです。

C または C++ でプログラミングしている場合は、C または C++ でプログラミングします。untilandは、一部の言語では頻繁にunless使用され、慣用的に使用される可能性がありますが、C または C++ では使用されません。

于 2011-04-09T19:26:57.207 に答える
17

あなたがやろうとしているのであれば、あなたがやった方法は正しい方法のように思えます。マクロの展開はあなたが期待するものと非常に似ているため[1]、マクロを構文 () のようにすることは有効だと思います。通常の構文には従わず、慎重に使用する必要があります。

[1] 唯一の欠点は、変数を宣言できないことです。とにかくありそうになく、間違って使用すると、奇妙なことをするのではなく、適切な場所でエラーが発生する可能性があります。

さらに、読みやすさのわずかな向上も重要であるため、実際until (の代わりに言うことができるとwhile (!、多くのループが読みやすくなります。終了条件が (そうであるかどうかに関係なく) 例外的な条件としてより簡単に考えられる場合、ループをそのように書くと読みやすくなります。構文糖衣にすぎませんが、検討する理由はあると思います。

しかし、私はそれが価値があるとは思わない。ほとんどのプログラマーは読み取りに慣れてif (!おり、その代償は現実のものであるため、メリットはわずかです。コードを読む人は、これがマクロなのかカスタム コンパイラーなのか、自分の考えどおりに動作するかどうかを確認する必要があります。そして、誤解を招くように、次のようなことができると思わせるかもしれませんi=5 unless xxxx;。このような小さな改善が広まると、言語が分断されてしまうため、多くの場合、標準的な方法で物事を行い、改善をゆっくりと採用するのが最善です。

ただし、うまく実行できます。boost と tr1 の全体、特にテンプレートを使用してライブラリの拡張機能のように見えるものには、さまざまな方法で C++ を拡張することが含まれますが、その多くは価値がないと思われたため採用されませんでした。しかし、それらの多くは実際の改善を行ったため、小規模または非常に広く普及しています.

于 2011-04-12T11:10:54.700 に答える
13

これは私が誰かのコードで見たことを思い出しました:

#define R return;

また、コードがわかりにくくなると、メンテナンス コストが増加します。

于 2011-04-09T19:30:46.970 に答える
8

それらを使用しない方が良いと思います。

これらを Ruby スタイルで次のように使用することはできません。

`printf("hello,world") unless(a>0);`

違法です。

また、C プログラマーがコードを理解するのはさらに難しくなります。一方、余分なマクロが問題になる可能性があります。

于 2011-04-09T19:29:28.990 に答える
5

マクロが自分のコードベースでのみ使用されている場合は特に悪いとは思いません。 この記事 はあなたにとって興味深いかもしれません。そうは言っても、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その後に句を追加することはできません。

于 2011-04-09T20:36:28.783 に答える
5

マクロを定義する場合は、見栄えを悪くすることをお勧めします。特に、すべて大文字にする必要があり、何らかの接頭辞を付ける必要があります。これは、名前空間がなく、C++ の型システムまたはオーバーロード解決との調整がないためです。

したがって、マクロが呼び出された場合BIGYAN_UNNECESSARY_MACRO_UNTIL、それは「見当違い」ではありません。

新しいループ構造で C++ を拡張したい場合は、C++0x でラムダを調査することを検討してください。

until([&] { return finished; }, [&] 
{
    // do stuff
});

完璧ではありませんが、マクロよりはましです。

于 2011-04-09T19:30:34.127 に答える
2

Boostforeachがどのように行われるかを見てください。

ヘッダーはBOOST_FOREACH(醜い接頭辞付きマクロ)を定義します。あなたはできる

#define foreach BOOST_FOREACH

よりクリーンなコードにするために、.cppファイルを使用します。ただし、.hファイルでこれを行うのではなく、代わりに醜いBOOST_FOREACHを使用してください。

さて、これが「便利な」IF THEN ELSE式のための「関数型プログラミングっぽい」マクロのセットです(?:が醜いため):

#define IF(x) (x) ?
#define ELSE :

int x = IF(y==0) 1
        ELSE IF(y<0) 2*y
        ELSE 3*y;

脱糖化:

int x = (y==0) ? 1 : (y<0) ? 2*y : 3*y;
于 2011-04-09T23:51:07.790 に答える
2

良い構文シュガーの例 (IMHO):

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
于 2012-08-22T08:30:25.040 に答える
1

人々が言っ​​たように、これらの単語を追加しても、実際には有用な構文糖衣は提供されません。なぜなら、while ( または if (! を読み取るコストは小さいためです。すべての C 開発者は慣れており、そのようなマクロを使用すると、ほとんどのC 開発者. また、ある言語を別の言語のように見せることは良い考えではありません。

しかし、シンタックス シュガーは重要です。std::make_pair(a, b)すでに述べたように、C++ では、テンプレートを介して多くのシンタックスシュガーを追加し、stl もソンム シュガーを提供します (たとえば、std::pair<decltype(a), decltype(b)>(a, b).

言語が改善されるにつれて、機能と構文糖衣の両方が追加され、開発者の読みやすさ、書きやすさ、および効率が向上します。たとえば、C++11 仕様では、「for (データ構造の要素)」が追加され (以下を参照)、型の 1 週間の推論を可能にする「auto」キーワードも追加されました (弱いと言うのは、型を入力する必要があるためです)。タイプが実際には「明白」で冗長な多くの場所での多くのタイプ)。

また、haskell では、do 記法 (シンタックス シュガー) なしでモナドを使用するのは非常に苦痛であり、誰も使用していません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 モナドの 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++ よりも柔軟であり、演算子 (たとえば、&^、+.、:+:、...) を作成できるため、誰かが再びシンタックス シュガーをすぐに導入することが想像できます :)。

于 2013-07-22T12:49:59.280 に答える