7

私は最近、この気の利いたスニペットをWebで見つけました。これにより、明示的なプレースホルダーを渡さなくてもバインドできます。

template <typename ReturnType, typename... Args>
std::function<ReturnType(Args...)> 
easy_bind(ReturnType(*MemPtr)(Args...))
{
  return [=]( Args... args ) -> ReturnType { return (*MemPtr)( args... ); };
}

このバージョンは、引数なしでうまく機能します。

auto f1 = easy_bind( (std::string(*)(A&,A&))&Worker::MyFn );

後で呼び出されます:

std::string s = f1( *p_a1, *p_a2 );

質問

最大n個の引数で動作するようにコードを変更して、2-n(この場合)にプレースホルダーを入力することは可能ですか?たとえば、これには1つのプレースホルダーが必要です。

auto f2 = easy_bind( (std::string(*)(A&,A&))&Worker::MyFn, *p_a1 );     

後で呼び出されます:

std::string s = f2( *p_a2 );

ボーナス

最終的には、このようなもの(最後のプレースホルダーを使い果たすため、プレースホルダーを挿入しない)があると便利ですが、この実装では機能しないと思います(署名のパターンマッチングはできないと思います)。

auto f3 = easy_bind( f2, *p_a2 );     

後で呼び出されます:

std::string s = f3();

肝心なのは、プレースホルダーを配置する必要のないバージョンのバインドがあると便利です。これは、一般的なTMPコードで非常に役立ちます。

4

2 に答える 2

16

インデックスのトリックあなた自身のプレースホルダータイプについて話す能力std::bindで、これが私が思いついたものです:

#include <functional>
#include <type_traits>
#include <utility>

template<int I> struct placeholder{};

namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::

namespace detail{
template<std::size_t... Is, class F, class... Args>
auto easy_bind(indices<Is...>, F const& f, Args&&... args)
  -> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...))
{
    return std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1>{}...);
}
} // detail::

template<class R, class... FArgs, class... Args>
auto easy_bind(std::function<R(FArgs...)> const& f, Args&&... args)
    -> decltype(detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...))
{
    return detail::easy_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, std::forward<Args>(args)...);
}

実例。

関数の引数easy_bindが型std::functionであるか、それに変換可能である必要があることに注意してください。これにより、明確な署名を使用できるようになります。

于 2013-02-22T13:17:51.063 に答える
0

当時の引数がわからない状況で関数をバインドしなければならなかったので、これは私にとって非常に厄介でした。(ここに示すようなファクトリC ++でシリアル化を実装する方法

たとえば(TSubClass :: createが静的であると仮定します)

template<typename TFactoryClass, typename TArgs...>
class Factory
{
public:
    template<typename TSubClass>
    void register(int id)
    {
         _map.insert(std::make_pair(id, std::bind(&TClass::create, /*how to give TArgs as placeholders??*/)));
    }
}

代わりに、これらすべてのヘルパークラスを使用せずに、std :: bindをラムダ式に置き換えることができました!

template<typename TFactoryClass, typename TArgs...>
class Factory
{
public:
    template<typename TSubClass>
    void register(int id)
    {
         _map.insert(std::make_pair(id, [](TArgs... args) { TSubClass::create(args...); }));
    }
}

ボーナスとして、このメカニズムでコンストラクターに「バインド」することもできます

于 2017-01-01T09:15:05.457 に答える