まず、小さな背景:後で呼び出されるコールバックをバインドします。これにより、ログを通じた制御フローに従うことが難しくなります。これを助けるために、我々はシステムを通過するときに要求に従うことを可能にする「ログコンテキスト」を使用します。現在のコンテキストを静的関数log_context::get_current
でコピーし、静的関数log_context::set_current
で復元することができます。これにより、コールバックをワーカー・キューにポストするたびに、繰り返しコードが多数発生します。C++:std :: bindの引数を取得します。
私は現在log_context
を保存し、呼び出されたときにそれを復元するstd::bind
のドロップイン置換である関数を作りたいと思います。しかし、私はそれを書くのにいくつかの問題を抱えています。
今、関数は次のようになります。それは作品
template <typename TResult,
typename... TFuncArgs,
typename Func,
typename... TProvidedArgs
>
std::function<TResult (TFuncArgs...)>
bind_with_context(const std::function<TResult (TFuncArgs...)>& throwaway,
Func func,
TProvidedArgs&&... args
)
{
log_context cxt = log_context::get_current();
auto bound = std::bind(func, std::forward<TProvidedArgs>(args)...);
auto lambda = [cxt, bound] (TFuncArgs... args) -> TResult
{
log_context::set_current(cxt);
return bound(args...);
};
return lambda;
}
が、問題は、使用量がありません本当の理由のために関数型を渡す必要がありますですが(それはさておき、私は何をして見つける方法です)TFuncArgs
のために使用します。
bind_with_context(func_type(), &some_class::some_func, ptr, _1, "Bob", _2);
だから、ないかなりのドロップイン置換。コンパイル時にががこの情報を知っているべきであると思われます。私は方法を理解できません。ほぼです。です。 関数の型を渡す必要性をどのように排除できますか?
私の最初の考えはそうのような関数に変換からの結合を分割することでした:
template <typename Func>
struct context_binder
{
public:
context_binder(const Func& func) :
func(func)
{ }
// Use the casting operator to figure out what we're looking for:
template <typename TReturn, typename... TFuncArgs>
operator std::function<TReturn (TFuncArgs...)>() const
{
log_context cxt = log_context::get_current();
auto lambda = [func, cxt] (TFuncArgs... args) -> TReturn
{
log_context::set_current(cxt);
return func(std::forward<TFuncArgs>(args)...);
};
return lambda;
}
private:
Func func;
};
template <typename F, typename... TArgs>
auto bind_with_context(F f, TArgs&&... args)
-> context_binder<decltype(std::bind(f, std::forward<TArgs>(args)...))>
{
return std::bind(f, std::forward<TArgs>(args)...);
}
問題は、キャスト(operator std::function<TReturn (TFuncArgs...)>() const
)は(int foo(int x, int y, int z)
与えられた)と呼ばれることはありませんということです。
std::function<int (int)> f = bind_with_context(&foo, 4, 5, _1);
理由はfunction
のコンストラクタからoperator()
をつかむしようとしていることですcontext_binder
(それがない場合でも)。
In file included from scratch.cpp:1:0:
/usr/local/include/gcc-4.6.2/functional: In static member function ‘static _Res std::_Function_handler<_Res(_ArgTypes ...), _Functor>::_M_invoke(const std::_Any_data&, _ArgTypes ...) [with _Res = int, _Functor = context_binder<std::_Bind<int (*(int, int, std::_Placeholder<1>))(int, int, int)> >, _ArgTypes = {int}]’:
/usr/local/include/gcc-4.6.2/functional:2148:6: instantiated from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type) [with _Functor = context_binder<std::_Bind<int (*(int, int, std::_Placeholder<1>))(int, int, int)> >, _Res = int, _ArgTypes = {int}, typename std::enable_if<(! std::is_integral<_Functor>::value), std::function<_Res(_ArgTypes ...)>::_Useless>::type = std::function<int(int)>::_Useless]’
scratch.cpp:53:85: instantiated from here
/usr/local/include/gcc-4.6.2/functional:1764:40: error: no match for call to ‘(context_binder<std::_Bind<int (*(int, int, std::_Placeholder<1>))(int, int, int)> >) (int)’
だから、これはほぼ解決のために、私の質問は:代わりfunction
のコンストラクタを使用しようとしているの私のキャストアウト演算子を好むg++
を取得する方法はありますか?
template <typename Func>
struct context_binder
{
private:
Func func;
log_context cxt;
public:
context_binder(const Func& func) :
func(func),
cxt(log_context::get_current())
{ }
template <typename... TArgs>
auto operator()(TArgs&&... args) const
-> decltype(func(std::forward<TArgs>(args)...))
{
log_context::set_current(cxt);
return func(std::forward<TArgs>(args)...);
}
};
template <typename F, typename... TArgs>
auto bind_with_context(F f, TArgs&&... args)
-> context_binder<decltype(std::bind(f, std::forward<TArgs>(args)...))>
{
return std::bind(f, std::forward<TArgs>(args)...);
}
誰かが割り当てしようとしたときTArgs
に膨張が起こるcontext_binder
非整数ためstd::function
(そのコンストラクタに:
'const std :: function&throwaway、Func func'を' TResult(Class :: *)(TFuncArgs ...) 'に置き換えてみませんか?結果のタイプは推論可能です。 –
Lol4t0
私はそれについて考えました。あなたは、 'class'に' const'と 'volatile'修飾子をつけて非メンバ関数にバインドできます。 9つの過負荷を持つことはひどいことではありません。 –
あなたのコンパイラが[* this']のためのセマンティクスをサポートするならば、それは9以上の過負荷です(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm) 。 – ildjarn