1. ホーム
  2. c++

[解決済み] なぜ独自の匿名型を持つ言語を設計するのか?

2023-03-14 06:46:57

疑問点

C++のラムダ式の特徴として、ずっと気になっていることがあります。C++ のラムダ式の型はユニークで匿名なので、単純に書き留めることができません。C++のラムダ式の型は一意であり、匿名であるため、書き出すことができない。たとえ構文的に全く同じ2つのラムダを作成したとしても、結果の型は別個であると定義されている。その結果、a) ラムダはコンパイル時にオブジェクトと一緒に型が渡せるようなテンプレート関数にしか渡すことができない。 std::function<> .

しかし、これはC++がそうしているだけで、私はこの言語の厄介な機能として片付けようと思っていました。しかし、Rust も同じようで、Rust の各関数またはラムダはユニークな無名型を持っていることを知りました。そして今、私は不思議に思っている。なぜでしょうか?

そこで、私の質問はこれです。

言語設計者の視点から、言語に一意な無名型の概念を導入する利点は何でしょうか?

どのように解決するのですか?

多くの標準 (特に C++) は、コンパイラーに要求することを最小限に抑えるというアプローチをとっています。 率直に言って、すでに十分に要求しています! 動作させるために何かを指定する必要がない場合、実装を定義したままにする傾向があります。

ラムダが匿名でないのであれば、我々はそれを定義しなければならないでしょう。 これは、変数がどのように捕捉されるかについて多くを語らなければならないだろう。 ラムダの場合について考えてみましょう [=](){...} . 型は実際にラムダによって捕捉された型を指定する必要があり、それを決定することは自明ではないかもしれません。 また、コンパイラが変数の最適化に成功した場合はどうだろうか? 考えてみましょう。

static const int i = 5;
auto f = [i]() { return i; }

最適化するコンパイラーは i の値が 5 であることを認識し、これを auto f = []() { return 5; } . しかし、型が匿名でない場合、これは型を変更する可能性があります または を格納し、コンパイラがより少なく最適化するよう強制します。 i を保存するように強制します。 これは、ラムダが行うことを意図していない、複雑でニュアンスのある全体の袋です。

そして、実際に非匿名型が必要な場合は、いつでもクロージャクラスを自分で構築し、ラムダ関数ではなくファンクタで作業することができます。 このように、ラムダは99%のケースを処理し、1%のケースではあなた自身の解決策をコード化するようにすることができるのです。


Deduplicatorはコメントで、私が匿名性と同じくらい一意性を扱っていないことを指摘しました。 私は一意性の利点についてあまり確信していませんが、型が一意である場合、次の動作が明確であることは注目に値します (アクションは 2 回インスタンス化されます)。

int counter()
{
    static int count = 0;
    return count++;
}

template <typename FuncT>
void action(const FuncT& func)
{
    static int ct = counter();
    func(ct);
}

...
for (int i = 0; i < 5; i++)
    action([](int j) { std::cout << j << std::endl; });

for (int i = 0; i < 5; i++)
    action([](int j) { std::cout << j << std::endl; });

もし型が一意でなかったら、この場合どのような動作が起こるかを指定しなければならないでしょう。 それは厄介なことかもしれません。 匿名性のトピックで提起された問題のいくつかは、一意性のこのケースでも頭をもたげます。