使用最少的复制转发仿函数

时间:2014-10-13 17:46:59

标签: c++ c++11 functor c++14 perfect-forwarding

我想转发仿函数调用并仅在绝对必要时复制该仿函数。这是我的通用包装函数和仿函数:

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

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

我可以用

调用包装器
  1. 右值引用:wrapper(Functor());
  2. 左值参考:Functor f;包装物(F);
  3. const lvalue reference :const Functor f;包装物(F);
  4. const rvalue reference :const Functor make_functor(); wrapper(make_functor());
  5. 我想在传递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运算符()

    来运行Functor
    struct Functor {
      Functor() {}
      void operator() () const {}
    };
    

    在这种情况下,我根本不需要复制包装器的arg。

    问题是:如果 Functor 具有const括号运算符,我如何检查包装器?另一个问题是,如果包装器可以更智能和更紧凑的方式实现,而没有大量的类型特征类型typedef? (实际上我不担心代码大小而是关于代码可读性)。

1 个答案:

答案 0 :(得分: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>());
}