C ++でのゴルフのヒント


48

C ++でゴルフをするための一般的なヒントは何ですか?私は少なくともC ++に特有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントを削除する」は答えではありません)。回答ごとに1つのヒントを投稿してください。


4
Cでのゴルフヒントの多くはC ++にも適用されるため、読者はその質問に精通していると想定してください。有効なCゴルフのヒントではないものがある場合にのみ、ここに投稿してください。
トビーSpeight

@TobySpeightおそらく、質問ID以外に同じURLがあるためです。
-NoOneIsHere

「ゴルフ」タイプでなくても、CとC ++は適切で簡単です(C ++の適切なサブセットを検討する場合)
RosLuP

回答:


24

三項条件演算子は?:、多くの場合、単純なためでスタンドとして使用することができますif- elseかなりの節約に文。

次のように代替の左辺値を選択するために使用できるという点で特別な値です。

#include <iostream>
#include <cstdlib>
int main(int c, char**v){
  int o=0,e=0,u;
  while(--c) ((u=atoi(v[c]))%2?o:e)+=u;
  std::cout << "Sum of odds " << o <<std::endl
            << "Sum of evens " << e <<std::endl;
}

まだコードを実行していませんが、あなたの言う通りに動作するとは思いません。((u = atoi(v [c]))%2?o:e)+ = uは、値oまたはeを取得する左側の式に値uを追加するだけですが、変数oおよびe変更されないため、常に0になります。コードをチェックして、何が起こるかを確認します。それを動作させるためにアドレスを使用する必要があります
ボグダンアレクサンドルー

4
@BogdanAlexandru Er ...それを実行してください。本当に機能します。括弧で囲まれた式の値は、eandのいずれかへの参照oです。これは、cでこの演算子がどのように機能するかとは異なります。この場合、このトリックは左辺値になれないため機能しません。
dmckee

置き換えstd::endl'\n'5文字節約
ムクルクマール

3
@MukulKumarええ、はい。しかし、このヒントを示すために、明確にするために、三項条件付きのゴルフ以外のすべてを残しました。
dmckee 14年

22

静的ストレージ期間変数(特にすべてのグローバルスコープ変数を含む)が先頭で自動的にゼロで初期化されるという事実を使用して、2文字を保存できる場合があります(このような保証がない自動変数とは異なります)。の代わりに

int main()
{
  int a=0;
  // ...
}

あなたは書ける

int a;
int main()
{
  // ...
}

+1、しかし間違いなく悪い練習
mondlos

@mondlos:ゴルフは基本的に悪い練習を意味します。
celtschk

15

一部のコンパイラ(GCCなど)は、複数文字の定数をサポートしています。これにより、大きな整数値が必要な場合に数文字を節約できます。例:

int n='  ';

値は実装固有です。通常の値が'ab'あります256*'a'+'b''a'+256*'b'。引用符の間に最大4文字を指定できます。


3
GCC?あなたはg ++を意味しますか?
ネイサンオスマン

6
@George Edison:GCCはGNU Compiler Collectionの略で、C、C ++、Goなどのフロントエンドを含むすべてのフロントエンドを網羅しています。
Joey Adams

@Joey:知っていますが、それはGNU Cコンパイラの名前でもあります。
ネイサンオスマン

25
@George:GNU Cコンパイラは、GCCではなくgccと呼ばれます。
fredoverflow

それを忘れないでください。

12

私が便利だと思ったもの:

ゼロ以外の値trueがブール式でx&&y評価されx*y、ブール値を処理するときに評価されるという事実を利用する

(x!=0 && y!=0)

に評価する

(x*y)

以下で指摘するように、オーバーフローに注意する必要があります。


2
技術的には、x!=0 && y!=0です。ただし、乗算を使用する場合は、オーバーフローに注意する必要があります。32ビット整数x = y = 65536(および他の2のべき乗の組み合わせ)を使用すると、x * y = 0も生成されます
マーティンエンダー14

はい、そうです。ここでは、2次元配列の境界チェックとして使用しました:codegolf.stackexchange.com/a/37571/31477ここで、それは重要ではありません。私は中にこれらのポイントを編集します。
Baldrickk

1
ただし、&&これに*は短絡動作がありません。たとえば、あなたが交換することはできませんi++!=0&&j++!=0i++*j++
celtschk

@celtschkはい、良い点です。しかし、もしあなたが純粋にブール代数をしているなら、それは動作します
Baldrickk

11

次のタイプを使用します。

u64, s64, u32, s32 (or int)

繰り返される単語/タイプには、次を使用します#defines

#define a while

while余分な10文字を補うために多くを使用する場合にのみ価値があります。(約4。


1
タイプu64、s64、u32、およびs32はC ++の一部ではありません。これらは、コンパイラの非標準の拡張機能である可能性があります(ただし、これまで見たことはありません)。
celtschk 14

5
これらの2つのヒントは、個別に投票できるように、2つの別々の回答に配置する方が適切です。
センモウヒラムシ


10

可能な場合は、それぞれ&&||を変更&|ます。

単純なifステートメントを使用する場合:

if(<condition>)<stuff>;

次のように変更できます。

<condition>?<stuff>:<any single letter variable>;

キャラクターを保存します。


8

を使用する代わりにwhile(1)、使用してfor(;;)、1文字を保存します:)


8

句に複数のステートメントが含まれる場合は、開き括弧と閉じ括弧の代わりにコンマ演算子を使用すると、数文字を節約できます。

if(c){x=1;cout<<"Hi";y=2;}else{x=2;cout<<"Bye";y=3;}

if(c)x=1,cout<<"Hi",y=2;else x=2,cout<<"Bye",y=3;###

プレーンIFで保存された2文字、またはIF / ELSEで合計3文字。

CとC ++の区別のポイントとして、C ++全体のコンマ式の結果は、左辺値... FWIWとして使用できます。


7

配列要素は、次のようなものではなく、メモリ内に次々と直接格納されるため:

for(int x = 0; x < 25; x++) {
    for(int y = 0; y < 25; y++)
        array[x][y] = whatever;
}

次のようなことができます:

int* pointer = array;
for(int i = 0; i < 25*25; i++, pointer++)
    *pointer = whatever;

明らかに、上記のどちらも読みやすくするためにゴルフされていませんが、明示的にポインターを使用すると、多くのスペースを節約できます。


空白をすべて削除できることを忘れないでください!(すべて異なるヒント、ただし言及する必要があります)
確率14

@stokasticこの例は、ゴルフを使用するためのものではなく、テクニックの使用方法を示すためのものです。
スタンデュッデ14

6
どうしてfor(int* i=array; i<array+25*25; i++)?次に、1つの変数のみを追跡する必要があります。
ルーカス

6

かなり明白なものですが、多くの標準ライブラリを使用しているusing namespace std;ため、数文字を節約できます。


5
ただし、単一の名前のみを使用している場合、それは非常に頻繁に使用されますが、using std::name;短くなる場合があります。
celtschk 14

10
これは、std::5回以上使用する場合にのみ文字を保存します。
nyuszika7h 14年

6

覚えておくと便利ですが、それa[i]はと同じ*(a+i)です。

2文字節約a[0]する*aために置き換えます。また、a[i][0]と同等で*a[i]あり、にa[0][i]縮小しi[*a]ます。したがって0、配列内のインデックスをハードコーディングしている場合、おそらくより良い方法が存在します。


5

10のべき乗を書く代わりに、e notationを使用します。たとえば、a=1000000000はより長いですa=1e9。これは、のような他の番号に拡張することができるa=1e9+24よりも優れていますa=1000000024


1
これは完全に同等ではなく、使用する前に整数型にキャストする必要があることに注意してください。たとえば、またはと1e9/x1000000000/x異なりint(1e9)/xます。
user202729

5

?:trueブロックに式を指定せずに三項演算子を使用できます(バイトを保存します)

#include <iostream>

int foo()
{
    std::cout << "Foo\n";
}

int main()
{
    1?foo():0;  // if (true) foo()
    0?:foo();   // if (!false) foo()
}

ここで確認してください


5
これはGNU拡張機能であり、C ++標準ではないようです。https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Conditionals.html#Conditionals
ceilingcat

r?foo():0; // if(r)foo()これで問題ありません;;;;; しかし、このr?:foo(); わからない
-RosLuP

5

短いヘッダー

これはGCC固有であり、他のコンパイラーに拡張可能です。

プリコンパイル済みヘッダー。

G ++ではbits/stdc++.h、プリコンパイル済みヘッダーは他のすべてのヘッダーで構成されます。もしあなたが必要ならばimport2つの異なるものな場合は、これを使用できます。

短いヘッダー。

これは、http://en.cppreference.com/w/cpp/headerにリストされているすべてのヘッダーです。

長さの昇順でソートされます。

それらのいくつかは、すでによりも長くbits/stdc++.h、それらのいくつかはC ++ 17サポートを必要とします。他のいくつかはTIO G ++でサポートされていません(理由はわかりません)。持っているものを除外します:

それらのいくつかはより短いもので置き換えることができるかもしれません。必要なものを置き換えることができるかどうかのバイナリ検索。特に:

cstdio -> ios        (-3 bytes)
algorithm -> regex   (-4 bytes)
vector -> queue      (-1 byte)
string -> map        (-3 bytes)
bitset -> regex      (-1 byte)
numeric -> random    (-1 byte)

4

#import の代わりに #includeもう1バイト与えます。

また、#importヘッダーとヘッダーの間のスペース文字は必ずしも次のとおりではありません。

#include <map>
// vs
#import<map>

また、stdlibヘッダーから何かが必要な場合は、の代わりにSTLコンテナー(優先setまたはmap)でヘッダーをインポートできますcstdlib


3

ブールの算術演算:

でも

a*=b>0?.5:-.5

よりも良い

if(b>0)a*=.5;else a*=-.5;

あまり良くない

a*=(b>0)-.5

また、よく使用されるものには#defineを使用します。多くの場合、型名は必要ないため、関数を使用するよりも短くなります。

可能な限り組み合わせる

a+=a--;

と同じです

a=2*a-1;

例は正しいですがx、左辺値およびx++右辺値として使用する場合、未定義の動作を呼び出すことに注意してください。未定義の動作とシーケンスポイント
-ceilingcat

はい、可能a + = a--; 未定義の動作がある
-RosLuP

3

一般的なラムダを安価なテンプレートとして使用する

以外の型の場合int、関数の引数として使用するとコストが高くなる可能性があります。ただし、一般的なラムダが(C ++ 14で?)導入され、任意のラムダをテンプレートにautoすることができます- 引数型に使用するとバイトを節約できます。比較:

double f(double x, double y)
[](auto x, auto y)

C ++での配列の入力を受け入れるように、おそらく最良の方法である-ジェネリックラムダも受け入れてイテレータのために非常に便利です[](auto a, auto z)azとして渡されるbegin()end()などのアレイ/ベクトル/リスト/で。


2

タスク「次の数字を引く」のコードゴルフの最初の試みで、関数から開始しました(58バイト)

int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}

その後、ラムダにシフトし、for(53)から初期化を移動して、5バイトを安全にします

[](int N,int P){int F=N;for(;P;F-=++N,P--);return F;}

そして最後にからに切り替えた後forwhile私は51バイトを得ました:

[](int N,int P){int F=N;while(P--)F-=++N;return F;}

テストされていないコードは次のようなものです:

#include <iostream>
int main(void)
{
    int N, P;
    std::cin >> N >> P;
    auto f = [](int N,int P)
    {
        int F = N;
        while (P--)
            F -= ++N;
        return F;
    };
    std::cout << f(N, P) << std::endl;
    return 0;
}

更新:

実際にfor同じ長さに達することができますwhile

[](int N,int P){int F=N;for(;P--;F-=++N);return F;}

2

パーティーに遅刻したようだ...

式をこれの代わりに0と1ではなく-1と1に変換する場合:

int x;
if (a * 10 > 5)
    x = 1;
else
    x = -1;

これを行う:

int x = (a * 10 > 5) * 2 - 1;

使用状況に応じて、いくつかのバイトを節約できます。


の代わりにint x=(a*10>5)*2-1;int x=a*10>5?1:-1;1バイト短くなっていますか?
ギロブス

2

2つの整数変数aとbを交換する場合、

a^=b^=a^=b;

使用することができ、標準的な方法よりも5文字を節約する

a+=b;
b=a-b;
a-=b;

1
その標準的な方法について。,tintで以前に作成されて、それからt=a;a=b;b=t;既に3バイト短くなっていたでしょうa+=b;b=a-b;a-=b;。それでも、あなたa^=b^=a^=b;はそれよりもさらに短いので、私から+1。私はC ++を知りませんが、実際に動作します。Javaコードゴルファーとしては、そこではうまくいかないようです。:(
ケビンクルーッセン

1
@KevinCruijssenええ、私はC ++に言及すべきだった、私はJavaをあまり知らないがa^=b;b^=a;a^=b;、Javaでうまく働いている。
joker007

1
C ++を明示的に述べる必要はありません。これらのヒントはすべてC ++向けです。:) Java開発者として、Javaで同様のことができるかどうかに興味がありましたが、明らかにそうではありませんでした。a^=b;b^=a;a^=b;実際に動作しますが、,t+ よりも長くなりt=a;a=b;b=t;ます。Javaはここでは話題にならないため、言及するのは残念です。しかし、C ++のコードゴルファーには良いヒントです!
ケビンクルーッセン

2

インポートする代わりにGCCビルトインを使用する

GCCコンパイラを使用している場合、__builtin_putsまたはなどの組み込み関数を使用すると役立つ場合があります__builtin_clz。例えば、

44バイト:

int main(){__builtin_puts("Hello, world!");}`

50バイト:

#import<cstdio>
int main(){puts("Hello, world!");}

1

C ++ 11以降を実行している場合(現在は常にそうであるはずです)、使用します auto可能であれば、複合型にしてください。

例:66ではなく54バイト

#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}

また、パフォーマンスは重要ではないため、一部の課題でstd::listは、数バイト少ないジョブを実行できます。

#include<list>
auto f(std::list<int> l){return l;}

1

の関数は、実際には長い<algorithm>パスa.begin(),a.end()を必要とすることが多く、代わりにis またはの&a[0],&*end(a)場合aは3バイトを節約できます。vectorstring

sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));

0

使用しないでくださいstring("")、使用を""。8バイトを節約します。


完全に同等ではありません。例えば"" + 'a'あるchar* + charながら、ポインタ加算である、std::string("") + 'a'であるstd::string + char-文字列の連結。string()動作します。
user202729
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.