2017-08-12 11 views
1

のパラメータをキャプチャ機能からラムダ式を返す:C++:次の関数は、多項式の係数を取り、そこから時間の関数を作成することになっている機能

std::function<double(double)> to_equation(const std::vector<double>& coefficients) 
{ 
    return [coefficients](double t) 
    { 
     auto total = 0.0; 
     for (int i = 0; i < coefficients.size(); i++) 
     { 
      total += coefficients[i] * pow(t,i); 
      return total; 
     } 
    }; 
} 

それが使用可能でなければなりません次のように

std::vector<double> coefficients = {1.0,2.0,3.0}; 
auto f = to_equation(coefficients); 
auto value = f(t); 

コードしかしながら意図したとおりf(t)の実行時に、to_equation(coefficients)に渡さ係数が使用されないので、動作が、魔法のようにCONTからキャプチャいくつか全く異なる値ありません内線何が起こっているのですか?それをどうやって修正できますか?

答えて

1

まあ、値でcoefficientsをキャプチャするラムダを返しています。ベクトルをto_equation関数に渡すと、すべての値がコピーされ、ラムダはもはや元のベクトルを参照しません。

std::function<double(double)> f; 

{ 
    std::vector<double> coeff{0.2, 0.4, 9.8}; 

    f = to_equation(coeff); 
} 

auto result = f(3); 

これは悪いです、ベクトルcoeffが十分に長く住んでいない、と私たち:あなたはいつかこのようなコードに対処しなければならない、しかし

// auto is faster than std::function 
auto to_equation(const std::vector<double>& coefficients) 
{ 
    // Here, you capture by reference. 
    // The lambda will use the vector passed in coefficients 
    return [&coefficients](double t) 
    { 
     // ... 
    }; 
} 

私はこの解決策を提案しますベクトルが破壊された後にそれを参照してください。

私はあなたの関数には、このオーバーロードを追加することをお勧め:

// when a vector is moved into coefficients, move it to the lambda 
auto to_equation(std::vector<double>&& coefficients) 
{ 
    // Here, you capture by value. 
    // The lambda will use it's own copy. 
    return [coeff = std::move(coefficients)](double t) 
    { 
     // ... 
    }; 
} 

次に、あなたの関数を呼び出すと、両方の方法で可能です:

std::vector<double> coeff{0.2, 0.4, 9.8}; 

auto f1 = to_equation(coeff); // uses reference to coeff 
auto f2 = to_equation({0.2, 0.4, 9.8}) // uses value moved into the lambda 
1

値ではなく参照でキャプチャできます。もちろん、ラムダが呼び出される前に根底にあるベクターが範囲外になって破壊された場合は、あなたの手に大きな混乱が生じます。

最も安全な方法は、プレーンベクトルの代わりにstd::shared_ptr<std::vector<double>>を使用し、それを値でキャプチャすることです。それでラムダは、最も最近の係数のセットであっても常に本質的にフィードし、根底にあるベクトルへの他のすべての参照の後に呼び出されると、爆発することはありません。

(元のラムダのすべてのコピーが同じベクトルを使用するため、ラムダがコピーされた場合、ここで何が起きるか注意する必要があります)。

詳細については、ラムダを使用する際に値と参照の取り込みの違いを説明するC++ブックの章を開きます。

関連する問題