「バブルパラドックス」とc ++


37

ここで記事を読んでいた:http : //www.paulgraham.com/avg.htmlそして「blub paradox」に関する部分は特に興味深いものでした。主にc ++でコーディングしているが、他の言語(主にHaskell)にさらされている人として、これらの言語ではc ++で複製するのが難しいいくつかの便利なことを知っています。質問は、主にc ++と他の言語の両方に習熟している人に対するものですが、c ++のみで記述している場合は概念化や実装が難しい言語で使用する強力な言語機能やイディオムはありますか?

特に、この引用は私の注意を引きました:

帰納法により、さまざまな言語間の力の違いをすべて見ることができるプログラマーは、最も強力な言語を理解しているプログラマーだけです。(これはおそらく、Eric RaymondがLispを使ってより良いプログラマーにしたことを意味するものです。)他の人の意見は、Blubパラドックスのために信頼できません。彼らがプログラムについて考える方法。

私がc ++を使用することで「Blub」プログラマと同等であることが判明した場合、次の質問が発生します。他の言語で遭遇し​​た概念化が難しいと思われる有用な概念やテクニックはありますかC ++で書いているか、「考えている」?

たとえば、PrologやMercuryなどの言語に見られるロジックプログラミングパラダイムは、キャスターライブラリを使用してc ++で実装できますが、最終的には概念的にPrologコードの観点から考えており、これを使用する場合はc ++の同等物に翻訳しています。プログラミングの知識を広げる方法として、C ++開発者としては知らないかもしれない他の言語でより効率的に表現される有用な/強力なイディオムの他の同様の例があるかどうかを見つけようとしています。思い浮かぶもう1つの例は、Lispのマクロシステムです。プログラム内からプログラムコードを生成すると、いくつかの問題に対して多くの利点があるようです。これは、c ++内から実装して考えることは難しいようです。

この質問は、「c ++ vs lisp」の討論や、あらゆる種類の言語戦争型の討論を意図したものではありません。このような質問をすることが、私が知らないことを知らないことを知ることができる唯一の方法です。



2
同意する。これがC ++対Lispの議論にならない限り、ここで学ぶべきことがあると思います。
jeffythedragonslayer

@MasonWheeler:-Lisp there are things that other languages can do that Lisp can'tはチューリング完全なので、ありそうもない。おそらく、あなたはLispで行うのが実用的でないいくつかのことがあると言うつもりでしたか?プログラミング言語について同じことが言えます。
ロバートハーベイ

2
@RobertHarvey:「すべての言語はチューリングと同等の意味で同様に強力ですが、それはプログラマーが気にする言葉の意味ではありません。(チューリング機械をプログラムしたい人はいません。)正式に定義できますが、それを説明する1つの方法は、より強力な言語のインタープリターを作成することで、より強力でない言語でしか取得できない機能を指すと言うことです。-ポール・グラハム、問題のトロルポストの脚注。(私が意味するものを参照してください?)
メイソンウィーラー

@メイソン・ウィーラー:(実際はそうではありません。)
ロバート・ハーベイ

回答:


16

さて、あなたはHaskellに言及したので:

  1. パターンマッチング。パターンマッチングは読み取りと書き込みがはるかに簡単であることがわかりました。マップの定義を検討し、パターンマッチングのない言語でマップをどのように実装するかを考えてください。

    map :: (a -> b) -> [a] -> [b]
    map f [] = []
    map f (x:xs) = f x : map f xs
  2. 型システム。痛みを伴うこともありますが、非常に役立ちます。それと実際にそれがキャッチするバグの数を理解するためにそれでプログラムする必要があります。また、参照の透明性は素晴らしいです。Haskellでプログラミングした後、命令型言語で状態を管理することによっていくつのバグが引き起こされるかが明らかになります。

  3. 一般的な関数型プログラミング。反復の代わりにマップと折り畳みを使用します。再帰。より高いレベルで考えることです。

  4. 遅延評価。繰り返しますが、より高いレベルで考え、システムに評価を処理させることです。

  5. カバル、パッケージ、およびモジュール。Cabalのダウンロードパッケージがあると、ソースコードを見つけたり、メイクファイルを作成したりするよりもはるかに便利です。


2
パターンマッチングに関する注意:一般的に書くのは簡単だとは言いませんが、式の問題を少し読んだ後、ifやswitchステートメント、enum、observerパターンなどがすべて代数データ型の劣った実装であることが明らかになります+パターンマッチング。(さらにたぶん、nullポインタ例外が時代遅れになりますどのように始めるのではないLETS)
hugomgを

あなたの言うことは本当ですが、表現の問題は代数データ型の制限に関するものです(そして標準的なOOPの二重の制限に関するものです)。
ブレイザーブレード

@hugomg Observerの代わりにVisitorパターンを意味しましたか?
セバスチャンレッド

はい。私は常にこれら2つの名前を切り替えます:)
hugomg

@hugomg持つことではなくMaybe(C ++についてはを参照std::optional)、オプション/ヌル可能/多分として明示的にマークする必要があります。
デデュプリケーター

7

メモ!

C ++で書いてみてください。C ++ 0xでは使用できません

面倒すぎる?さて、それをしよう C ++ 0xの。

Dのこの4行(または5行、何でも:P)のコンパイル時バージョンに勝てるかどうかを確認します。

auto memoize(alias Fn, T...)(T args) {
    auto key = tuple(args);                               //Key is all the args
    static typeof(Fn(args))[typeof(key)] cache;           //Hashtable!
    return key in cache ? cache[key] : (cache[key] = Fn(args));
}

それを呼び出すために必要なことは次のようなものです:

int fib(int n) { return n > 1 ? memoize!(fib)(n - 1) + memoize!(fib)(n - 2) : 1;}
fib(60);

また、Schemeでも同様のことを試すことができますが、実行時に発生し、ここでの検索はハッシュではなく線形であるため(そしてSchemeだからです)、少し遅くなります:

(define (memoize f)
    (let ((table (list)))
        (lambda args
            (cdr
                (or (assoc args table)
                    (let ((entry (cons args (apply f args))))
                        (set! table (cons entry table))
                        entry))))))
(define (fib n)
        (if (<= n 1)
            1
            (+ (fib (1- n))
                (fib (- n 2)))))))
(set! fib (memoize fib))

1
それで、あなたは一行で何かを書くことができるAPLが好きですか?サイズは関係ありません!
ボーパーソン

@Bo:APLは使用していません。「サイズは関係ありません」とはどういう意味なのかわかりませんが、私のコードに何か問題があると言っていますか?そして、私が知らない別の言語(C ++など)でこれを行う方法にはいくつかの利点がありますか?(変数名を少し編集しましたが、それがあなたが参照していた場合です。)
Mehrdad

1
@Mehrdad-私のコメントは、最もコンパクトなプログラムが最高のプログラミング言語のサインではないということです。その場合、ほとんどのことを単一のchar演算子で行うため、APLが勝ちます。唯一の問題はそれが読めないことです。
ボーパーソン

@Bo:私が言ったように、私はAPLを推奨していませんでした。私も見たことがありません。サイズは1つの基準でした(C ++でこれを試してみるとわかるように、重要な基準ですが)...しかし、このコードには何か問題がありますか?
Mehrdad

1
@Matt:コード関数をメモしましが、このコードは任意の関数をメモできます。これらはまったく同等ではありません。C ++ 0xでこのような高階関数を実際に書いてみると、Dよりもずっと退屈です(まだ可能ですが、C ++ 03では不可能です)。
Mehrdad

5

C ++はマルチパラダイム言語です。つまり、多くの考え方をサポートしようとします。関数型プログラミングの場合のように、C ++の機能は他の言語の実装よりも扱いにくいか流でない場合があります。

そうは言っても、yieldPythonやJavaScriptでできることを行うネイティブC ++言語機能の頭の外を考えることはできません。

別の例は、並行プログラミングです。C ++ 0xにはそれについての発言権がありますが、現在の標準にはありません。並行性はまったく新しい考え方です。

また、迅速な開発-シェルプログラミングでさえ-C ++プログラミングの領域を離れることがなければ、決して学ぶことはありません。


C ++ 2003を与えられたC ++でジェネレーターを作成するのがどれほど難しいか考えることさえできません。C ++ 2011を使用すると簡単になりますが、それでも簡単ではありません。C ++、C#、Pythonを定期的に使用することで、ジェネレーターは簡単にC ++で最も見逃しがちな機能になります(C ++ 2011でラムダが追加されました)。

私はこのために撃たれることを知っていますが、C ++でジェネレーターを絶対に実装しなければならなかった場合、... setjmpとを使用する必要がありlongjmpます。私はそれがどれほど壊れるかわからないが、例外は最初に行くと思う。さて、すみませんが、Modern C ++ Designを読み直して頭から外す必要があります。
マイクデシモーネ

@Mike DeSimone、setjmpとlongjmpを使用してソリューションをどのように試行するかについて(簡単に)詳しく説明できますか?

1
コルーチンはファンクターと同型です。
-GManNickG

1
@ Xeo、@ Mike:xkcd.com/292
Mehrdad

5

コルーチンは非常に便利な言語機能であり、他の言語がC ++よりも多くの具体的なメリットを提供します。これらは基本的に追加のスタックを提供するため、機能を中断して継続することができ、パイプラインのような機能を言語に提供し、フィルターを介して他の操作に操作の結果を簡単に提供します。それは素晴らしく、Rubyでは非常に直感的でエレガントだとわかりました。遅延評価もこれに関連しています。

イントロスペクションとランタイムコードのコンパイル/実行/評価/その他は、C ++にはない非常に強力な機能です。


コルーチンは、Cで実装されている FreeRTOS(こちらを参照)で利用できます。C++で動作させるには何が必要でしょうか?
マイクデシモーネ

コルーチンは、Cでオブジェクトをエミュレートする厄介なハックです。C++では、オブジェクトを使用してコードとデータをバンドルします。しかし、Cではできません。そのため、データを保存するにはコルーチンスタックを使用し、コードを保持するにはコルーチン関数を使用します。
MSalters


1
@Ferruccio:リンクをありがとう...ウィキペディアの記事にもいくつかあります。@MSalters:何がコルーチンを「厄介なハック」と表現するのですか?私には非常にarbitrary意的な見方があるようです。スタックを使用して状態を保存することも再帰アルゴリズムによって行われます-それらもハックされていますか?FWIW、コルーチン、OOPはほぼ同時期に登場しました(1960年代初期)...前者はCのオブジェクトのハックとは奇妙に思えます... C ++の15年前。
トニー

4

LispとC ++の両方でコンピューター代数システムを実装したので、私はLispでの作業がはるかに簡単であったことを伝えることができます。リストであるすべてのもののこの単純な性質は、非常に多くのアルゴリズムを単純化します。確かに、C ++バージョンは何十倍も高速でした。ええ、私はLispバージョンをより高速にできたかもしれませんが、コードはリッピーではありません。スクリプティングは、たとえばLispを使用することで常に簡単になります。仕事に適切なツールを使用することがすべてです。


速度の違いは何ですか?
quant_dev

1
@quant_dev:もちろん、数十億の倍数です!
マットエレン

実際に測定したことはありませんが、大きなOが違うと感じました。私はもともと機能的なスタイルでC ++バージョンを作成しましたが、新しい変更されたものを作成する代わりにデータ構造を変更するように教えるまで、速度の問題もありました。しかし、それはまたコードを読みにくくしました
...-jeffythedragonslayer

2

ある言語が別の言語よりも「強力」であると言うとき、私たちは何を意味しますか?言語が「表現力がある」と言うとき。または「金持ち?」私は考えていない、本当に状態遷移-私たちは、その視野が十分に狭く、言語獲得能力は、それが簡単かつ自然な問題を記述するために作成することを意味ですか?-それはその視野の中に住んでいます。しかし、その言語は、視野が広がると、かなり強力で、表現力が低く、有用性が低くなります。

言語が「強力」かつ「表現力豊か」であるほど、その使用はより制限されます。そのため、「強力な」と「表現力のある」は、狭いユーティリティのツールに使用する間違った言葉です。たぶん、「適切な」または「抽象的」がそのようなことのより良い言葉です。

私はプログラミングで、低レベルのものをたくさん書くことから始めました。割り込みルーチンを備えたデバイスドライバー。組み込みプログラム; オペレーティングシステムコード。コードはハードウェアと密接であり、すべてアセンブリ言語で記述しました。アセンブラーが最も抽象的であるとは言いませんが、それでもアセンブラーは最も強力で表現力のある言語です。アセンブリ言語で問題を表現できます。どんなマシンでも好きなことをできるほど強力です。

そして、後に高水準言語を理解したことはすべて、アセンブラーでの経験にすべてを負っています。後で学んだことはすべて簡単でした。なぜなら、あなたは、すべてが-どんなに抽象的なものであっても-最終的にはハードウェアに適応する必要があるからです。

抽象化のレベルが高いこと、つまり、視野が狭くなることを忘れたくなるかもしれません。あなたはいつでも後でそれを拾うことができます。数日で習得するのは簡単です。私の意見では、ハードウェア1の言語を学び、できるだけ骨に近づいた方が良いでしょう。


1 おそらく完全に密接な関係ではありませんが、ハードウェアからその名前carcdr取ります。最初のLispは、実際の減分レジスタと実際のアドレスレジスタを持つマシンで実行されました。それはどうですか?


その選択は両刃の剣であることがわかります。私たちは皆それを求めますが、それには暗い面があり、私たちを不幸にします。世界を明確に定義し、操作できる境界を定義することをお勧めします。人々は非常に創造的な生き物であり、限られたツールで素晴らしいことをすることができます。要約すると、プログラミング言語ではなく、あらゆる言語を歌わせる才能のある人がいるということです!
チャド

「提案することは作成することであり、定義することは破壊することです。」別の言語で生活が楽になると思うのは気持ちがいいですが、一度ジャンプしたら、新しい言語のいぼに対処する必要があります。
マイクデシモーネ

2
英語はどのプログラミング言語よりも強力で表現力がありますが、その有用性の限界は日々広がり、その有用性は計り知れません。力と表現力の一部は、適切な抽象化レベルでコミュニケーションをとることができること、新たに抽象化されたときに新しい抽象化レベルを発明する能力にあります。
molbdnilo

@Mikeその後、新しい言語内で以前の言語と通信する必要があります;)
チャド

2

連想配列

データを処理する一般的な方法は次のとおりです。

  • 入力を読み取り、そこから階層構造を構築します。
  • その構造のインデックスを作成する(異なる順序など)
  • それらの抽出物(フィルター部分)を作成し、
  • 値または値のグループ(ノード)を見つける、
  • 構造を再配置します(ノードの削除、追加、追加、ルールに基づいたサブ要素の削除など)。
  • ツリーをスキャンして、それらの一部を印刷または保存します。

適切なツールは連想配列です。

  • 私が見た連想配列の最適な言語サポートはMUMPSですです。連想配列は次のとおりです。1.常にソートされる2.まったく同じ構文でディスク(いわゆるデータベース)に作成できます。(副作用:データベースとして非常に強力で、プログラマーはネイティブbtreeにアクセスできます。NoSQLシステムとしては最高です。)
  • 私の2番目の賞はPHPです。foreachと、$ a [] = xまたは$ a [x] [y] [z] ++のような簡単な構文が好きです

JavaScriptの連想配列構文はあまり好きではありません。たとえばa [x] [y] [z] = 8を作成できないため、最初にa [x]a [x] [y]を作成する必要があります。

さて、C ++(およびJava)には、コンテナクラスMapMultimapの素晴らしいポートフォリオがあります一切は、しかし、私はをスキャンしたい場合、私はイテレータを作るために持っている、と私は新しい深いレベルの要素を挿入したいとき、Iすべての上位レベルなどを作成する必要があります。不快。

C ++(およびJava)には使用可能な連想配列がないとは言いませんが、型のない(または厳密ではない型付きの)スクリプト言語は、型のないスクリプト言語であるため、コンパイルされた言語よりも優れています。

免責事項:C#やその他の.NET言語には精通していませんが、連想配列が適切に処理されていることはわかっています。


1
完全開示:MUMPS は万 向けで はありません引用:MUMPSであるホラーのもう少し「実世界」の例を挙げるために、まず、国際難読化Cコードコンテストの一部、Perlのダッシュ、FORTRANとSNOBOLの2つのヒープメジャー、および医学研究者の数十人、そしてそこに行きます。
マイクデシモーネ

1
Pythonでは、組み込みdict型のいずれかを使用できます(たとえばx = {0: 5, 1: "foo", None: 500e3}、キーまたは値が同じ型である必要はないことに注意してください)。a[x][y][z] = 8言語は、値を設定するのか、別のレベルを作成するのかを確認するために、将来を調べる必要があるため、次のようなことをしようとするのは困難です。表現a[x][y]自体ではわかりません。
マイクデシモーネ

MUMPSは元々、連想配列を使用したBasicに似た言語です(直接ディスクに保存できます!)。それ以降のバージョンには手続き型拡張機能が含まれており、コアPHPに非常によく似ています。BasicとPHPを恐れる人は、おたふくかぜが恐ろしいと思うはずですが、そうでない人もいます。プログラマーはしません。そして、それは非常に古いシステムであり、1文字の指示(フルネームを使用することもできます)、LR評価順序などのすべての奇妙なもの-奇妙なソリューションと同様に-唯一の目標があります:最適化
ern0

「私たちは小さな効率を忘れて、時間の約97%を言うべきです。時期尚早な最適化はすべての悪の根源です。しかし、その重要な3%で機会を逃すべきではありません。」- ドナルドクヌース。あなたが説明することは、後方互換性に重点を置いたレガシー言語のように聞こえますが、それは大丈夫です。個人的に、それらのアプリケーションでは、保守性が最適化よりも重要であると考えています。非代数的表現と1文字のコマンドを備えた言語は逆効果に聞こえます。言語ではなく、お客様にサービスを提供します。
マイクデシモーネ

@マイク:あなたが投稿した非常に面白いリンク、私はそれらを読んでいる間大笑いしました。
シャトル87

2

私は、Java、C \ C ++、アセンブリ、およびJavaスクリプトを学びません。私はC ++を使って生計を立てています。

ただし、アセンブリプログラミングとCプログラミングの方が好きだと言わざるを得ません。これは主に命令型プログラミングとインラインです。

プログラミングパラダイムは、データ型を分類し、高度なプログラミング抽象概念を提供して、強力な設計パターンとコードの形式化を可能にするために重要であることを知っています。ある意味では、各パラダイムはパターンのコレクションであり、基礎となるハードウェアレイヤーを抽象化するコレクションです。したがって、EAXやマシン内部のIPについて考える必要はありません。

これに関する私の唯一の問題は、機械がどのように機能するかという人々の概念と概念を、何が起こっているのかというイデオロギーと曖昧な主張に変えることです。このパンは、プログラマーのイデオロギーの目標に対するアブストラクトに加えて、あらゆる種類の素晴らしいアブストラクションです。

結局のところ、CPUが何であるか、およびコンピューターが内部でどのように動作するかについて、明確で明確な考え方と境界を持つことが望ましいです。CPUが気にするのは、データをメモリに出し入れしてレジスタに移動し、命令を実行する一連の命令を実行することです。データ型の概念、またはより高度なプログラミングの概念はありません。データを移動するだけです。

プログラミングパラダイムをミックスに追加すると、世界の見方がすべて異なるため、より複雑になります。


2

C ++のみで記述している場合、概念化または実装が難しい言語で使用する強力な言語機能またはイディオムはありますか?

他の言語で出会った便利な概念やテクニックのうち、C ++で書いたり「考えたり」していたとしたら概念化が難しいと思うものはありますか?

C ++は多くのアプローチを扱いにくいものにします。プログラミングのほとんどは、C ++に限定すると概念化するのが難しいとまで言います。C ++が困難にする方法ではるかに簡単に解決できる問題の例を次に示します。

レジスタ割り当てと呼び出し規約

多くの人がC ++をベアメタルの低レベル言語と考えていますが、実際はそうではありません。マシンの重要な詳細を抽象化することにより、C ++はレジスタ割り当てや呼び出し規約などの実用性を概念化することを困難にします。

このような概念について学ぶために、いくつかのアセンブリ言語プログラミングを試してみることをお勧めします。ARMコード生成の品質に関するこの記事をご覧ください。

実行時コード生成

C ++のみを知っているなら、おそらくテンプレートはメタプログラミングのすべてであり、すべてであると思うでしょう。そうではありません。実際、これらはメタプログラミングのための客観的に悪いツールです。別のプログラムを操作するプログラムは、インタープリター、コンパイラー、コンピューター代数システム、定理証明器などのメタプログラムです。実行時コード生成は、このための便利な機能です。

EVALメタサーキュラー評価について学ぶために、Scheme実装を起動して遊ぶことをお勧めします。

木を操作する

ツリーはプログラミングのどこにでもあります。構文解析では、抽象構文ツリーがあります。コンパイラには、ツリーであるIRがあります。グラフィックとGUIプログラミングには、シーンツリーがあります。

この「C ++用の途方もなくシンプルなJSONパーサー」は、C ++では非常に小さい484 LOCの重さです。ここで、F#のわずか60 LOCの重さの単純なJSONパーサーと比較してください。違いは主に、MLの代数的データ型とパターンマッチング(アクティブパターンを含む)によってツリーの操作が非常に簡単になるためです。

OCamlの赤黒木もチェックしてください。

純粋に機能的なデータ構造

C ++でのGCの欠如により、いくつかの有用なアプローチを採用することは事実上不可能になります。純粋に機能的なデータ構造はそのようなツールの1つです。

たとえば、OCamlのこの47行の正規表現マッチャーをご覧ください。簡潔さは、主に純粋に機能的なデータ構造の広範な使用によるものです。特に、設定されたキーを持つ辞書の使用。stdlibの辞書とセットはすべて変更可能ですが、辞書のキーを変更したりコレクションを壊したりすることはできないため、C ++で行うのは非常に困難です。

論理プログラミングとアンドゥバッファは、純粋に機能的なデータ構造が、C ++では難しいものを他の言語では非常に簡単にする、実際的な例です。

テールコール

C ++は末尾呼び出しを保証しないだけでなく、デストラクタが末尾位置で呼び出しの邪魔になるため、RAIIは基本的にそれと対立します。テールコールを使用すると、制限された量のスタックスペースのみを使用して、無制限の数の関数呼び出しを行うことができます。これは、拡張可能なステートマシンを含むステートマシンの実装に最適であり、多くの場合厄介な状況で優れた「脱獄」カードです。

たとえば、金融業界のF#でメモを使用した継続渡しスタイルを使用して、0-1ナップザック問題のこの実装を確認してください。テールコールがある場合、継続渡しスタイルは明らかな解決策になる可能性がありますが、C ++では扱いにくくなります。

並行性

別の明らかな例は、並行プログラミングです。これはC ++で完全に可能ですが、他のツールと比較して非常にエラーが発生しやすく、最も顕著なのは、Erlang、Scala、F#などの言語で見られるようなシーケンシャルプロセスの通信です。


1

これは古い質問ですが、誰もそれについて言及していないので、リスト(そして今は辞書)の内包表記を追加します。HaskellまたはPythonでFizz-Buzz問題を解決するワンライナーを書くのは簡単です。C ++でそれを試してください。

C ++はC ++ 11を使用して近代化に大規模に移行しましたが、「近代的な」言語と呼ぶのは少し手間がかかります。C ++ 17(まだリリースされていない)は、「現代」が「前の千年紀からではない」ことを意味する限り、現代の標準に到達するための動きをさらに増やしています。

Pythonで1行で記述できる(そしてGuidoの79文字の行の長さの制限に従う)最も簡単な理解でさえ、C ++に変換すると多くのコード行になり、C ++コードのこれらの行の一部はかなり複雑になります。


よく注意してください:私のプログラミングのほとんどはC ++です。私は言語が好きです。
デビッド

Ranges Proposalはこれを解決するはずだと思いましたか?(私は思うC ++ 17でもない)
マーティンBa

2
「現代への大規模な動き」:現在のミレニアムで発明されたC ++ 11が提供する「現代の」機能とは何ですか?
ジョルジオ

@MartinBa-「範囲」の提案に対する私の理解は、作業が簡単でエラーが発生しにくいイテレータの代わりになるということです。リスト内包表記と同じくらい面白いものを許可するという提案は見ていません。
ジュール

2
@Giorgio- 現在人気のある言語のどのような機能が現在のミレニアムで発明されましたか?
ジュール

0

ユーザー定義クラスのユーザー定義メンバー関数であるコールバックを呼び出すコンパイル済みライブラリ。


これはObjective-Cで可能であり、ユーザーインターフェースプログラミングを簡単にします。ボタンを伝えることができます:「押して、このオブジェクトに対してこのメ​​ソッドを呼び出してください」、ボタンはそうします。コールバックには任意のメソッド名を自由に使用できます。ライブラリコードでフリーズしたり、機能するためにアダプターから継承したり、コンパイル時に呼び出しを解決したりする必要はありません。同様に重要なことは、同じオブジェクトの2つの異なるメソッドを呼び出すように2つのボタンに指示できることです。

他の言語でコールバックを定義する同様の柔軟な方法はまだ見ていません(ただし、それらについて聞いてみたいと思います!)。C ++で最も近いものは、おそらく、必要な呼び出しを実行するラムダ関数を渡すことです。これにより、ライブラリコードがテンプレートに制限されます。

Objective-Cのこの機能により、言語があらゆる種類のオブジェクト/関数/言語に含まれる重要な概念を自由に渡し、それらを保存する能力を評価することを学びました変数。あらゆる種類の概念を定義しているが、利用可能なすべての種類の変数にそれを格納する手段(またはその参照)を提供しない言語のポイントは、重大な障害であり、おそらく非常にいソースです。複製されたコード。残念ながら、バロックプログラミング言語には、次のような点が多く見られる傾向があります。

  • C ++では、VLAのタイプを書き留めたり、VLAへのポインターを保存したりすることはできません。これにより、動的サイズの真の多次元配列(C99以降Cで使用可能)が事実上禁止されます。

  • C ++では、ラムダのタイプを書き留めることはできません。それをtypedefすることさえできません。したがって、ラムダを渡す方法や、ラムダへの参照をオブジェクトに格納する方法はありません。Lambda関数はテンプレートにのみ渡すことができます。

  • Fortranでは、名前リストのタイプを書き留めることはできません。あらゆる種類のルーチンに名前リストを渡す方法はありません。そのため、2つの異なる名前リストを処理できる複雑なアルゴリズムを使用している場合は、運が悪くなります。アルゴリズムを一度だけ記述して、関連する名前リストを渡すことはできません。

これらはほんの一例ですが、共通のポイントがあります。このような制限を初めて目にするときは、禁じられていることをするのは本当におかしいと思われるので、通常は気にしません。ただし、その言語で本格的なプログラミングを行うと、最終的にこの厳密な制限が実際の迷惑になります。


1
I have not seen a similarly flexible way to define a callback in any other language yet (though I'd be very interested to hear about them!) ここで説明することは、Delphiでのイベント駆動型UIコードの動作とまったく同じように聞こえます。(および.NET WinFormsでは、Delphiの影響を強く受けていました。)
メイソンウィーラー

2
「C ++では、VLAのタイプを書き留めることはできません」[...]-C ++では、C99スタイルのVLAは不要std::vectorです。スタック割り当てを使用しないため、効率はやや劣りますが、機能的にはVLAと同型であるため、「バブル」タイプの問題として実際にはカウントされません。C++プログラマーは、その動作を見て、 、CはC ++よりも効率的に処理します。」
ジュール

2
「C ++では、ラムダの型を書き留めることはできません。それをtypedefすることもできません。したがって、ラムダを渡す方法や、ラムダへの参照をオブジェクトに格納する方法はありません」-それstd::functionが目的です。
ジュール

3
「他の言語でコールバックを定義する同様の柔軟な方法を見たことはありません(それらについて聞いてみたいと思いますが!)。」-Javaでは、書くことができobject::method、インスタンスに変換されます。受信コードが期待するどんなインターフェースでも。C#にはデリゲートがあります。基本的に2つのパラダイムの断面のポイントであるため、すべてのオブジェクト関数言語にはこの機能があります。
ジュール

@Julesあなたの議論はまさにBlub-Paradoxの目的です。熟練したC ++プログラマとして、あなたはこれらを制限として見ていません。ただし、これらは制限であり、C99などの他の言語はこれらの特定の点でより強力です。あなたの最後の点まで:多くの言語で可能な回避策がありますが、メソッドの名前を他のクラスに渡し、提供するオブジェクトでそれを呼び出すことが本当にできる方法はわかりません。
cmaster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.