2017-10-31 6 views
2

this,this、潜在的にはthisに関する質問です。ファンクションシグネチャに応じた値/参照としてのバリアブルテンプレートの転送タイプ

私はAddFunctionメソッドは渡された引数で渡された関数を呼び出すstd::threadを生成します、その後、その関数への関数と引数のリストを受信する以下のクラス、持っている:これは、その結果

class Processes { 
public: 
    Processes() {} 

    ~Processes() { 
    for (auto &t : threads_) { 
     t.join(); 
    } 
    } 

    template <class Function, typename... Args> 
    void AddFunction(Function &&func, Args &&... args) { 
    threads_.emplace_back(std::forward<Function>(func), 
          std::forward<Args>(args)...); 
    } 

private: 
    std::vector<std::thread> threads_; 
} 

をオブジェクトがコピー可能でない場合は、は、std::refに参照がラップされている必要があるため、このオブジェクトがスレッドの有効期間を超えてコピーされます。

ターゲット関数の署名に指定されている場合は、参照によってオブジェクトを渡したいと思っています。

私は、ラムダを使用してみました:

template <class Function, typename... Args> 
void AddFunction(Function &&func, Args &&... args) { 
    threads_.emplace_back([&]() { func(std::forward<Args>(args)...); }); 
} 

しかし、ラムダが基準行動によってキャプチャが得られ、値で渡す前に参照によって値をキャプチャして、これは、不正な動作になります。

目的関数の署名に従って、引数を値または参照のいずれかとして転送する関数を実装するにはどうすればよいですか?


例:

void Foo(int a, std::vector<int> const &b) { /* ... */ } 

int main() { 
    Processes procs; 
    int a = 6; 
    std::vector<int> b; 
    procs.AddFunction(
    Foo, 
    a, // Should be passed by value 
    b // Should be passed by reference (as implemented by std::ref) 
); 
    return 0; 
} 

答えて

1

あなたは以下総称する関数のシグネチャを変更する場合があります:

まず、いくつかのヘルパー:

template <typename T> struct non_deducible { using type = T; }; 
template <typename T> using non_deducible_t = typename non_deducible<T>::type; 

template <typename T> 
auto passed_by(T& t, std::true_type) 
{ 
    return std::ref(t); 
} 

template <typename T> 
T&& passed_by(T&& t, std::false_type) 
{ 
    return std::forward<T>(t); 
} 

そして

template <class Ret, typename... Args> 
void AddFunction(Ret (*func)(Args...), non_deducible_t<Args>... args) { 
    threads_.emplace_back(func, 
          passed_by(std::forward<Args>(args), 
            std::is_reference<Args>{})...); 
} 
+0

は、これが問題を解決しました。私はあなたがこのようにして関数呼び出しを解くことができるのか分からなかった。 '{}'の構文は何ですか?それは空のコンストラクタですか?ありがとうございました! – jlicht

+0

はい、 'type {}'は 'type'の空のコンストラクタです。' {} '構文は' type() 'とは逆の場合もあります。 – Jarod42

2

あなたはラムダルートを下に移動したい場合は、あなたには、いくつかのユーティリティを実装することができallow you to capture by "perfect-forward"こと - これは右辺値が閉鎖に移動され、左辺値を参照することにより取得されることを意味します。あなたはTまたはT&は(私のリンク先の記事にはクリーナー実装を持っている)を保存するかstd::tuple<T>を使用することができます。

template <class Function, typename... Args> 
void AddFunction(Function &&func, Args &&... args) 
{ 
    threads_.emplace_back([ 
     targs = std::tuple<Args...>{std::forward<Args>(args)...}, 
     tfunc = std::tuple<Function>(func)]() mutable 
    { 
     std::apply([&targs](auto&& x_func) 
     { 
      std::apply([&x_func](auto&&... x_args) 
      { 
       std::forward<Function>(x_func)(
        std::forward<Args>(x_args)... 
       ); 
      }, targs); 
     }, tfunc); 
    }); 
} 

live wandbox example

関連する問題