c++ - 处理指向模板中成员的指针,同时创建更简单的 `bind` 以与 asio 一起使用

标签 c++ templates c++11

我想创建一个包装器来简化处理程序绑定(bind)的编写,这样我只需要提供回调和数据指针即可。

这是我的代码:

#include <utility>

template <typename Func, typename Data>
class Handler
{
   const Func & m_func;
   volatile Data & m_data;

public:
   Handler(const Func & f, Data & d) :
      m_func(f),
      m_data(d)
   {}

   Handler(const Handler & cpy) :
      m_func(cpy.m_func),
      m_data(cpy.m_data)
   {}

   template<typename Res=void, typename... Args>
   Res operator()(Args... args) const
   {
      return m_func(m_data, std::forward<Args>(args)... );
   }
};

/* I need help to handle this specialization */
template<typename T>
template<typename Res=void, typename... Args>
Res Handler<(T::*)(Args...), T*>::operator()(Args... args) const
{
   return (m_data->*m_func)(std::forward<Args>(args)... );
}


template <typename Func, typename Data>
inline Handler<Func, Data> handler(Func f, Data d)
{
   return Handler<Func, Data>(f, d);
}

目标是像这样使用它:

boost::asio::async_read(socket,
                        boost::asio::buffer(d, n),
                        handler(callback, session)
);

或者像这样:

boost::asio::async_read(socket,
                        boost::asio::buffer(d, n),
                        handler(&Object::method, this_ptr)
);

但我在处理后一种情况的特化时遇到问题...

最佳答案

如果您真的想编写自己的模板,那么您的模板中有很多需要修复的地方。首先,您要保留对临时对象的引用。您的 handler() 函数需要自己获取引用,或者您需要保留值。更愿意保持值(value)观。如果用户想要传递引用,他们总是可以使用 std::ref。让我们从那开始吧。这是一个带有数据的简单处理程序:

template <typename Func, typename Data>
struct Handler
{
   Func func;  // NB: not a reference
   Data data;

   template<class... Args>
   auto operator()(Args&&... args) const  // NB: this wasn't a forwarding ref before
       -> decltype(func(data, std::forward<Args>(args)...))
   {
      return func(data, std::forward<Args>(args)... );
   }
};

好吧,现在我们有了一个聚合,它已经是可复制和可移动的,我们想要的所有好东西都不必自己写出来(不是说你的 Handler 是可移动的 - 但移动它调用复制构造函数...)

现在,我们可以写出我们的函数了:

template <class F, class D>
Handler<std::decay_t<F>, std::decay_t<D>> handler(F&& f, D&& d) {
    return {std::forward<F>(f), std::forward<D>(d)};
}

要处理成员函数,您只需要单独重载handler。其他一切都保持不变,我们只是有条件地用 mem_fn 包装指向成员的指针:

template <class R, class T>
auto handler(R T::* p, T* cls)
    -> Handler<decltype(std::mem_fn(p)), T*>
{
    return {std::mem_fn(p), cls};
}

嗯瞧。

关于c++ - 处理指向模板中成员的指针,同时创建更简单的 `bind` 以与 asio 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39372213/

相关文章:

c++ - 使用 std::bind 的功能组合

c++ - 关于调用 srand 的说明

c++ - 执行 C++ CUDA 内核时黑屏,输出正确结果

c++ - 如何为依赖目标添加 cmake 定义?

c++ - 使用带有基类的模板作为参数

c++ - 未调用 move 构造函数

c++ - 获取准确的窗口区域大小 - CreateWindow 窗口大小不是正确的窗口大小

c++ - CUDA 代码在 Linux 上编译但在 Windows 上不编译(Visual Studio 2012)

c++ - 如何制作一个 C++ 模板类,根据模板值的类更改其成员和访问器?

C++ 通用指针函数或模板