Boost.Bind の protect 相当の関数を C++0x の に用意する

元ネタ: http://d.hatena.ne.jp/Flast/20110728/1311878870


(std|boost)::bind の結果を (std|boost)::bind に渡すと,特別扱いして関数合成を行ってくれるんだけど,それ邪魔な時があるよね.
boost::bind には protect があるけど, std::bind で同様のことって出来る? って話題.


それ Variadic Templates で出来るよ!

#include <utility>

template< class F >
struct protect_bind_t
{
  F f;

  template< class... Args >
  auto operator()( Args&&... args )
    -> decltype( f( std::declval<Args>()... ) )
  {
    return f( std::forward<Args>(args)... );
  }

  template< class... Args >
  auto operator()( Args&&... args ) const
    -> decltype( f( std::declval<Args>()... ) )
  {
    return f( std::forward<Args>(args)... );
  }

};

template< class F,
  class Result = protect_bind_t<typename std::decay<F>::type>
>
Result protect( F && f )
{
  return { std::forward<F>(f) };
}

#include <iostream>
#include <functional>

struct some_functor
{
  typedef bool result_type;
  template < typename Pred >
  bool operator()( Pred pred )
  { return pred( 1 ); }
};

int main()
{
  using namespace std::placeholders;
  
  auto f = std::bind(
    some_functor(),
    protect( std::bind( std::less< int >(), 0, _1 ) )
  );
  
  std::cout << std::boolalpha << f() << std::endl;
}

要するに bind の結果じゃなければ特別扱いされないので,ラップすれば問題ないよね,ってことです.


…と,ここまで書いて思ったけど,基本的に protect は bind の結果に対して使うしか用途がないので,この2つを合成して,

#include <utility>

template< class F >
struct protect_bind_t
{
  F f;

  template< class... Args >
  auto operator()( Args&&... args )
    -> decltype( f( std::declval<Args>()... ) )
  {
    return f( std::forward<Args>(args)... );
  }

  template< class... Args >
  auto operator()( Args&&... args ) const
    -> decltype( f( std::declval<Args>()... ) )
  {
    return f( std::forward<Args>(args)... );
  }

};

#include <functional>

template< class F, class... Args,
  class Result = protect_bind_t<
    decltype( std::bind( std::declval<F>(), std::declval<Args>()... ) )
  >
>
Result protect_bind( F && f, Args&&... args )
{
  return { std::bind( std::forward<F>(f), std::forward<Args>(args)... ) };
}

#include <iostream>

struct some_functor
{
  typedef bool result_type;
  template < typename Pred >
  bool operator()( Pred pred )
  { return pred( 1 ); }
};

int main()
{
  using namespace std::placeholders;
  
  auto f = std::bind(
    some_functor(),
    protect_bind( std::less< int >(), 0, _1 )
  );
  
  std::cout << std::boolalpha << f() << std::endl;
}

って書いたほうがいいかもですね.