web-dev-qa-db-ja.com

C ++ラムダをすぐに呼び出す方法は?

私が継承しているクラスのコンストラクターには、重要なオブジェクトを渡す必要があります。これと同様:

MyFoo::MyFoo() : SomeBase( complexstuff )
{
    return;
}

complexstuffMyFooとはほとんど関係がないため、渡す必要はありませんでした。

complexstuffを返すある種の一時的な関数を記述する代わりに、ラムダを使用しました。私が理解するのに数分かかったのは、ラムダをinvokeしなければならないことです。だから私のコードは次のようになります:

MyFoo::MyFoo() : SomeBase(
    []()
    {
        /* blah blah do stuff with complexstuff */
        return complexstuff;
    } () )
{
    return;
}

あなたがそれを捕らえなかったならば、それは微妙です。しかし、ラムダ本体の後に、()を入れて、コンパイラにラムダをすぐに「実行」するように指示する必要がありました。これは、自分が間違ったことを理解した後で理にかなっています。それ以外の場合、ラムダを呼び出す()がないと、gccは次のようなことを言います。

error: no matching function for call to 'SomeBase(<lambda()>)'

しかし、今、私はそれを考えています-私はこれを正しく行いましたか? C++ 11またはC++ 14で、作成したラムダをすぐに呼び出すようコンパイラーに指示するためのより良い方法はありますか?または、空の()を通常の方法で追加したように追加していますか?

14
Stéphane

しかし、今、私はそれを考えています-私はこれを正しく行いましたか?

はい、そうでした。

C++ 11またはC++ 14で、作成したラムダをすぐに呼び出すようコンパイラーに指示するためのより良い方法はありますか?

私が知っていることではありません。ラムダは単なる関数オブジェクトでもあるので、あなたはそれを呼び出すために()を必要とする、それを回避する方法はありません(ただし、もちろん、std::invoke)のようなラムダを呼び出すいくつかの関数。

必要に応じて、ラムダはパラメーターを一切使用しないため、キャプチャリストの後に()をドロップできます。

または、空の()を通常の方法で追加したように追加していますか?

はい、それが最短の方法です。前に述べたように、std::invokeも代わりに機能しますが、さらに入力する必要があります。 ()を使用した直接呼び出しが通常の方法だと思います。

14
Rakete1111

コンパイラにラムダをすぐに呼び出すように指示する方法はありません。最も単純なコース(複雑さと入力された文字の数の両方の点で)は、すでに行ったものです。また、クロージャーを持つ言語を使用したことがある人にとっては非常に慣用的です(ここではJavaScriptを考えています)。

構文を避けたい場合は、SomeBaseまたはcomplexstuffを変更して、呼び出し可能オブジェクトを実行します。


必要なのがラムダを呼び出すための構文糖である場合、AlexandrescuのSCOPE_GUARDのようなことをいつでも実行でき、演算子のオーバーロードを乱用します。

Live example

#include <iostream>

constexpr enum {} invoke{};

template<class Callable>
auto operator+(decltype(invoke) const&, Callable c) -> decltype(c()) {
    return c();
}


int main() {
    invoke + []() {
        std::cout << "called";
    };
}

しかし、私はしません。独自のDSLを発明すると、コードの維持管理が悪化するだけです。単純な言語構成を利用するイディオムに固執する。

C++ 17では std::invoke 。これはあなたがしたのと全く同じことを行いますが、おそらくこれがより明確になるでしょう。

#include <iostream>
#include <functional>

void foo(int i)
{
  std::cout << i << '\n';
}

int main()
{
  foo( std::invoke( []() { return 1; } ) );
}
4
Henri Menke

もっと良い方法はありますか

complexstuffを構築するプライベート静的メンバー関数を使用することも検討できます。

class MyFoo : public Base {
private:
    static SomeComplexType compute_complex_stuff() {
      SomeComplexType complexstuff;
      /*compute the complexstuff */
      return complexstuff;
    };
public: 
    MyFoo() : Base(compute_complex_stuff()) {};
};

ラムダ式を定義してすぐに適用するよりも良いかどうかはわかりません。それは私見の好みの問題です。 shortラムダ本体の場合、ラムダ式をすぐに適用することをお勧めします(ただし、一部のコンパイラーがその場合に一時クロージャーを作成するため、速度が遅くなる可能性があります)最適化なし;ほとんどのC++ 11コンパイラがその最適化を行えると期待しています)。

ところで、GCCは ステートメント式 言語拡張(Clangでも理解可能)を提供しています。それであなたは書くことができました

MyFoo::MyFoo : Base (({
  SomeComplexType complexstuff;
  /*compute the complexstuff */
  return complexstuff;
}) {};