2016-12-13 9 views
0

EDIT:std :: bind()の呼び出しを別のものに置き換えることができます。runAsyncTerminateOnException()をstd :: async()と同じシグネチャーで動作させたいだけです。 、それにラッパーのようにラッパーとstd :: async()が動作しない

私はstd :: async()へのラッパーを作成しようとしています。 std :: async()の直接呼び出しが機能するときに、ラッパーを動作させる方法を知っていますか?

注:print()関数のシグネチャは変更しません。これは一例です。私は、ラッパーを汎用的にし、std :: async()への直接呼び出しでうまく処理できるすべての可能なパラメーターで動作させたいと思います。

ありがとうございます。

http://ideone.com/HbBqeo

#include <iostream> 
#include <functional> 
#include <future> 

template<class Fn, class... Args> 
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) { 
    auto make_call = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...); 

    return std::async(std::launch::async, [=]() -> decltype(make_call()) { 
     try { 
      return make_call(); 
     } catch (...) { 
      std::cout << "Terminate Called!" << std::endl; 
      std::terminate(); 
     } 
    }); 
} 

struct Foo { 
    template<class... Args> 
    void print(Args&&... args) { 
     printf("Foo::print(%d)\n", std::forward<Args>(args)...); 
    } 
}; 

int main() { 
    Foo foo; 
    std::future<void> future = std::async(std::launch::async, &Foo::print<int>, &foo, 2); 
    std::future<void> future2 = runAsyncTerminateOnException(&Foo::print<int>, &foo, 2); 
    // your code goes here 
    return 0; 
} 

答えて

0

私はC++の解決策を見つけました。 runTerminateOnException()の戻り値の型にautoを使用しない場合にのみ機能します。

template<class Fn, class... Args> 
inline std::result_of_t<Fn&&(Args&&...)> runTerminateOnException(Fn&& fn, Args&&... args) { 
    try { 
     return std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...); 
    } catch (...) { 
     std::terminate(); 
    } 
} 

template<class Fn, class... Args> 
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) { 
    return std::async(std::launch::async, runTerminateOnException<Fn, Args&&...>, std::forward<Fn>(fn), std::forward<Args>(args)...); 
} 
2

あなたは次のようにあなたのrunAsyncTerminateOnException呼び出しを変更する必要があります。

std::future<void> future2 = 
    runAsyncTerminateOnException(&Foo::print<const int&>, &foo, 2); 

これはan unfortunate interaction between std::bind, variadic templates and perfect forwardingによるものです。

代わりにlambdasを使用することをお勧めします。これは、ほとんど常にstd::bindよりも優れています。 (詳細については、STLからthis talkを参照してください。)

template<class Fn> 
inline auto runAsyncTerminateOnException(Fn&& fn) 
{  
    return std::async(std::launch::async, [=]() -> decltype(fn()) { 
     try { 
      return fn(); 
     } catch (...) { 
      std::cout << "Terminate Called!" << std::endl; 
      std::terminate(); 
     } 
    }); 
} 

(私はラムダにfnをコピーしてることに注意してください - 。あなたはより正確かつ汎用的なソリューションをしたい場合、あなたはperfect-forward capturing the object into the lambdaを考慮する必要があります)

std::future<void> future2 = 
    runAsyncTerminateOnException([&foo]{ return foo.print(2); }); 

wandbox example

+0

ここで、runAsyncTerminateOnException()関数はstd :: async(std :: launch :: async、?)と同じシグネチャを持ちません。同じシグネチャでstd :: async()のラッパーを作成する方法、およびstd :: async()がこの問題をどのように解決するのか知っていますか?ありがとうございました – infiniteLoop

+0

@Vittorio Romeoあなたはコールバックがコピー可能であると仮定しますが、そうでないかもしれません。なぜそれをラムダに完璧にしようとしないのですか? –

+0

@DavidHaim:私は最近、[lambdaに完全転送の記事を書いた](https://vittorioromeo.info/index/blog/capturing_perfectly_forwarded_objects_in_lambdas.html)。この質問の範囲外の定型文/知識が必要ですが、注記を追加します。 –

関連する問題