4

ファンクター呼び出しを転送し、絶対に必要な場合にのみそのファンクターをコピーしたいと思います。これが私の一般的なラッパー関数とファンクターです:

template <typename F>
void wrapper (F func)
{
  func ();
}

struct Functor
{
  Functor() {}
  void operator() () { /* do some work */ }
};

ラッパーを呼び出すことができます

  1. 右辺値参照: wrapper( Functor() );
  2. 左辺値参照: ファンクター f; ラッパー(f);
  3. const 左辺値参照: const Functor f; ラッパー(f);
  4. const 右辺値参照: const Functor make_functor (); ラッパー (make_functor ());

const 参照が渡された場合にのみラッパーの arg をコピーしたい。だから私はそのようなラッパーの実装に来ます:

using safe_mutual_handler_type =
  typename std::conditional<
    std::is_reference<F>::value
  , typename std::conditional<
      std::is_const<typename std::remove_reference<F>::type>::value
    , typename std::remove_const<typename std::remove_reference<F>::type>::type
    , F&
    >::type
  , F&
  >::type;

template <typename F>
void wrapper (F&& func)
{
  safe_mutual_handler_type<F> tmp = func;
  tmp ();
}

あまり良くなく、(あまり典型的ではない)const-rvalue-referenceのケースを見逃していますが、基本的には機能します。

しかし、const operator() を持つ Functor もあるかもしれません

struct Functor {
  Functor() {}
  void operator() () const {}
};

その場合、ラッパーの引数をまったくコピーする必要はありません。

問題は、 Functorに const 括弧演算子がある場合、ラッパーをチェックインするにはどうすればよいかということです。もう 1 つの質問は、ラッパーが、膨大な数の型特性 typedefs の行なしで、よりスマートでコンパクトな方法で実装できるかどうかです。(実際には、コードのサイズではなく、コードの可読性について心配しています)。

4

1 に答える 1

5

呼び出しが有効な場合に参照を使用したいだけの場合は、式 SFINAE を使用します。

template <typename F>
auto wrapper_ (F&& func, int) -> decltype(func())
{
    func ();
}

template <typename F>
void wrapper_ (F func, ...)
{
    func ();
}

template <typename F>
void wrapper (F&& f)
{
    wrapper_(std::forward<F>(f), 0);
}

変更可能な参照を渡すときにのみコピー/移動したい場合(そしてその時のみ):

template <typename F>
auto wrapper_ (F&& func, std::true_type)
{
    func ();
}

template <typename F>
void wrapper_ (F func, std::false_type.)
{
    func ();
}

template <typename F>
void wrapper (F&& f)
{
    wrapper_(std::forward<F>(f), std::is_const<typename std::remove_reference<F>::type>());
}
于 2014-10-13T18:04:15.460 に答える