2017-06-06 8 views
8

コンパイラは、削除された関数(ラムダ式のコピーコンストラクタ)にアクセスしようとしていると伝えます。しかし、私はどこに見えません。要素をコピー可能でないベクトルに移動できないのはなぜですか?

std::vector<std::function<void()>> tasks; 
std::packaged_task<int()> task{ [] { return 1; } }; 
tasks.emplace_back(
    [ t = std::move(task) ]() mutable { t(); }); 

code is also here

(私は、彼らがhttps://www.slideshare.net/GlobalLogicUkraine/c11-multithreading-futuresshared_ptr<task>を使用する理由を見つけようとしています)。 GCCとMSVCで

私は同じエラーを取得する - 私は何か間違ったことをやっている恐れ...

error: use of deleted function 
'main()::<lambda()>::<lambda>(const main()::<lambda()>&)' 

は、なぜ私はベクトル上にこのstd::functionを据え付けることができませんか?

+1

[コピー不可能なstd ::関数をコンテナに格納する方法は?](質問/ 28208948 /保管方法 - コピー不可能 - コンテナへの保存方法) – cpplearner

+0

@cpplearnerありがとうございますすべてが「機能」に至り、CopyConstructableを指示していますか? – xtofl

答えて

4

にラムダをバインドする必要があります:

FはFstd::functionを構築するために使用される関数の型で呼び出し可能とコピーコンストラクト

の要件を満たす必要があります。ただし、std::packaged_tasknot copy constructibleです。したがって、キャプチャリストでtはコピーコンストラクタブルではなく、ラムダの非静的メンバであるため、ラムダの暗黙のコピーコンストラクタが削除されます。

+0

コピーコンストラクタは使用できませんが、コピーコンストラクタは使用できません。 'emplace_back([t] {})'にコピーコンストラクタが必要なのはなぜですか? – xtofl

+0

ああ! ''関数(F) 'のコンストラクタは呼び出されているので、ラムダを' '入れ替える 'ようにしています!それは分かります。ありがとう。 – xtofl

2

短い回答:Lambdasとstd::packaged_taskstd::functionではありません。ただいずれかをあなたが実際にはstd ::機能が必要な場合

std::vector<std::packaged_task<int()>> tasks; 
std::packaged_task<int()> task{ []() mutable { return 1; } }; 
tasks.emplace_back(std::move(task)); 

、およびない:

ロング答えは、あなたがここで私は解決策として提供するんだよstd::function

std::packaged_taskを移動することはできません呼び出し可能な、あなたはcppreferenceからstd::function

0

std::functionのコンストラクタでは、渡された関数オブジェクトはCopyConstructibleである必要がありますが、std::packaged_task<F>はありません(いずれでもF)。 std::functionは、の消去タイプを実行します。ここで、ダイナミックタイプはスタティックタイプでは表示されません。例えば考える:

int invoke(std::function<int()> f) { return f(); } 

int main() 
{ 
    std::packaged_task<int()> p{/*etc*/}; 
    auto l = [] { return 5; }; 
    std::function<int()> f(/* either p or l */); 
    std::cout << invoke(f) << '\n'; 
} 

invokeへの呼び出しは、(値渡し)コピーfを必要とします。ただし、flから作成された場合はコピー可能ですが、pから作成された場合はコピーできません。これはスタティックタイプfとは関係ありません。この問題に対する基本的なアプローチは3つあります。

  • コンパイル時にstd::functionを禁止します。
  • std::functionをコンパイル時に許可しますが、含まれている型がコピーできない場合は実行時エラーが発生します。
  • コンパイル時にstd::functionをコピーすることができます。また、コピーすることができるファンクションオブジェクトが必要です。

Approach#1は、関数の格納、渡し、共有の仕方が非常に限定されており、コピーできない関数オブジェクトを使用するという珍しいケースのために、一般的な使用例は基本的に禁じられています。

アプローチ2は、std::functionのコピーが失敗する場合があり、コードを記述する際に慎重を期する必要があるため、問題があります。また、デザインに共有機能が必要な場合は、std::shared_ptrにラップする必要があります。また、コピーしてステートフルにする必要がある場合は、さらに悪化します。

アプローチ3をどのように見ても、それは標準化されたものです。しかし、上記の問題に照らして、簡単に防御することもできます。

実際に私は現在のプロジェクトにアプローチ#1を使用するunique_functionクラステンプレートを書いています。なぜなら、コピーできない非同期タスクオブジェクトを格納するユースケースが非常に一般的であり、そのようなタスクは必要ありません。

関連する問題