2017-03-02 17 views
4
// By const l-value reference 
auto func2 = std::bind([](const std::unique_ptr< std::vector<int> >& pw) // fine 
{ 
    std::cout << "size of vector2: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 

//By non-const l-value reference 
auto func3 = std::bind([](std::unique_ptr< std::vector<int> >& pw) // fine 
{ 
    std::cout << "size of vector3: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 

// By Value 
auto func4 = std::bind([](std::unique_ptr< std::vector<int> > pw) // error 
{ 
    std::cout << "size of vector4: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 
func4(); // without this line, compilation is fine. The VS generates error for the calling of the bind object. 
// By r-value reference 
auto func5 = std::bind([](std::unique_ptr< std::vector<int> >&& pw) // error 
{ 
    std::cout << "size of vector5: " << pw->size() << std::endl; 
}, std::make_unique<std::vector<int>>(22, 1)); 
func5(); // without this line, compilation is fine. 

なぜfunc4とfunc5がコンパイルに失敗するのですか?std :: unique_ptrでlambdaのstd :: bindを使用する

+0

コードはVS2015で正常にコンパイルされます。あなたの側にエラーメッセージを表示してください。 –

+0

@Martin Zhai、行func4()またはfunc5()を追加すると、大量のエラーが表示されます。 – q0987

+1

主な問題は 'std :: bind'です。それが起きると、あなたはまた、最初の間違いをした後に(予想通りに)他のエラーを受け取ります。 – Yakk

答えて

4

func4は、ラムダのパラメータが値によって渡されるため、エラーが発生します。しかしstd::unique_ptrはコピー不可能です。

func5はより複雑である、我々はドキュメントstd::bindから読み取ることができます。それは、関数呼び出し式g(u1, u2, ... uM)、保存されたの呼び出しで呼び出されたときに、バインドする以前の呼び出しから取得したオブジェクトgを考えると

を下記の指定されたオブジェクトがstd::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))であるかのように、場所をとり、fdがバインド引数v1の値と型タイプstd::decay_t<F>の値であり、v2、...、vNが決定されます。
は...
argは左辺値引数として呼び出し可能なオブジェクトに渡され、通常の保存された引数:STDにおける引数vn ::コールが上記単にArgで起動し、対応するタイプVnT cv &CVありますgと同じcv-qualificationです。

std::make_unique<std::vector<int>>(22, 1)はr値であってもため、L値が予想r値と互換性のないラムダ、に与えられます。
func3が正常に動作する理由を説明することもできます。

2

bindは、複数回呼び出すことができる関数オブジェクトを返します。

引数をとり、それをタプル(または同等のもの)に格納します。次に、最初の引数を残りの引数とともに呼び出します。これはC++のstd::invokeに似ています。

失敗したケースでは、ラムダを2回以上呼び出すことができませんでした。 バインドは、再度呼び出すことができると仮定しているため、一度呼び出すとエラーが発生します。他のことをすることは、あなたがそれをoperator()の文脈で決して再び呼ぶことがないことを知ることができないので、狂気になるでしょう。

論理的には、これらのコールはである必要があります。は失敗します。標準では、この場合の標準が論理的に動作するため、失敗することも義務付けられています。ここで


auto funcA = 
    [pw=std::make_unique<std::vector<int>>(22,1)] 
    { 
    std::cout << "size of vector2: " << pw->size() << std::endl; 
    }; 

auto funcB = 
    [pw=std::make_unique<std::vector<int>>(22,1)]() mutable 
    { 
    std::cout << "size of vector2: " << pw->size() << std::endl; 
    }; 

あなたのコードがしたおおよそ何を二つの異なるラムダがあります。バインドとパスの代わりに、キャプチャします。 funcA

我々はfuncBに、我々は非constunique_ptrを持って、const unique_ptrを持っています。第二に、私たちはユニークなptrから移動することができます。最初は、できません。

std::bindは、C++に存在するラムダより前に書かれたものであり、ラムダを使用するよりもめったに良い考えではありません。ラムダの欠点はC++ 14でほとんど取り除かれており、ラムダの代わりにbindを使うのは良い考えです。

std::bindは、bindの結果を別のbindに渡すなど、奇妙なエラーメッセージを生成し、多くのコーナーケースでは不可解な動作をします。

関連する問題