2016-07-10 8 views
2

一部のC++ 11/14コードでセマンティクス(C++ 17ではstd::invokeで実装)を使用する必要があります。私は確かに自分自身を実装したくはありません。私はそれが災害であると信じています。そこで、私は現在の標準ライブラリ施設を利用することに決めました。すぐに私の心に来た:C++ 11/14 INVOKE回避策

template<typename Fn, typename... Args> 
constexpr decltype(auto) my_invoke(Fn&& f, Args&&... args) 
    noexcept(noexcept(std::bind(std::forward<Fn>(f), std::forward<Args>(args)...)())) 
{ 
    return std::bind(std::forward<Fn>(f), std::forward<Args>(args)...)(); 
} 

この実装に問題がoperator()() &operator()() &&上の関数オブジェクトのオーバーロード、唯一&&バージョンが今までになります場合には、例えば(左辺値と右辺値呼び出し可能オブジェクトを区別することはできませんですと呼ばれる)。呼び出し可能なものを完全に転送するライブラリユーティリティはありますか?そうでない場合、それを実装するにはどうすればよいでしょうか? (たとえば、転送ラッパー)。

+1

[cppreference](http://en.cppreference.com/w/cpp/utility/functional/invoke)のサンプル実装を参照してください。いくつかのC++ 17の機能を使用するかもしれませんが、おそらくC++で動作するように変更することができます。11/14 – Mankarse

答えて

1

INVOKEのすべての特別なケースは、メンバーへのポインタです。 SFINAEだけでそれをmem_fnに送ってください。

template<typename Fn, typename... Args, 
     std::enable_if_t<std::is_member_pointer<std::decay_t<Fn>>{}, int> = 0 > 
constexpr decltype(auto) my_invoke(Fn&& f, Args&&... args) 
    noexcept(noexcept(std::mem_fn(f)(std::forward<Args>(args)...))) 
{ 
    return std::mem_fn(f)(std::forward<Args>(args)...); 
} 

template<typename Fn, typename... Args, 
     std::enable_if_t<!std::is_member_pointer<std::decay_t<Fn>>{}, int> = 0> 
constexpr decltype(auto) my_invoke(Fn&& f, Args&&... args) 
    noexcept(noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...))) 
{ 
    return std::forward<Fn>(f)(std::forward<Args>(args)...); 
} 

これは基本的にN4169で提案されている最小限の実装です。 (本当の標準ライブラリの実装者は、INVOKE機能を一箇所に集約し、他のさまざまな部分を呼び出してもらうことがずっとメンテナンスできるので、これをしません)。std::bindを使用すると完全に間違っています。それはすべての引数をコピー/移動し、lvaluesとしてコール可能に渡し、reference_wrappers、プレースホルダ、およびバインド式で不要な魔法を実行します。

+0

Hmmはすべての引数を 'bind 'しませんか? –

+0

@ZizhengTai No. –

+0

ああ、私は間違っていた。したがって、 'bind'はすべての引数をコピー/移動し、内部的にそれらを格納します。最後に呼び出されると、格納されたコピーを呼び出し可能に転送します。あれは正しいですか? –