【问题标题】:How to assign same signature to functions with different signatures?如何将相同的签名分配给具有不同签名的函数?
【发布时间】:2012-08-23 21:05:53
【问题描述】:

在我的 C++ 应用程序中,我有 2 个线程:(i) 主线程,(ii) 后台线程。 我有一个类定义为:

class helper
{
 public:
     bool login(const string& username, const string& password);
     void logout();

 private:
     bool loginInternal(const string& username, const string& password);
     void logoutInternal();
}

helper::login() 和 helper::logout() 函数(以及其他几个具有各种返回类型和 # of params 和 param 类型的成员函数)在主线程上调用。在这些函数的实现中,对应的内部函数要入队,后台线程按照入队的顺序调用这些内部函数。所以是这样的:

bool helper::login(const string& username, const string& password)
{
    queue.push_back(boost::bind(&helper::loginInternal, this, username, password));
}

void helper::logout()
{
    queue.push_back(boost::bind(&helper::logoutInternal, this));
}

后台线程一直在运行,等待队列填满,一旦填满,这个后台线程就会开始调用队列中的函数:

queue.front()();
queue.pop_front();

那么问题来了,我该如何定义这样的队列呢?

deque<???> queue;

此队列的数据类型可能是什么,以便它可以在同一队列中保存具有不同签名的回调函数?

编辑: 这是解决方案(感谢 J. Calleja):

typedef boost::function<void ()> Command;
deque<Command> queue;

然后像这样调用仿函数:

// Execute the command at the front
Command cmd = queue.front();
cmd();

// remove the executed command from the queue
queue.pop_front();

【问题讨论】:

    标签: c++ function pointers boost functor


    【解决方案1】:

    如果你规范化返回类型或忽略它,你可以使用boost::function。该库定义了一个包装器,可以存储任何与您的签名(函数或函子)匹配的元素。

    用你的例子:

    #include <boost/function.hpp>
    
    class helper 
    {  
    public:      
      bool login(const std::string& username, const std::string& password);
      void logout();
    private:      
      bool loginInternal(const std::string& username, const std::string& password);
      void logoutInternal();
    private:
      typedef boost::function<void ()> Command;
      std::deque<Command> queue;
    };
    

    此示例忽略返回类型,因为它声明了返回 void 的函数。如果你想知道返回值,你必须让 logout 返回一个 bool 并将声明更改为:

      typedef boost::function<bool ()> Command;
    

    【讨论】:

      【解决方案2】:

      我相信第一个类型是bind&lt;bool&gt;,第二个类型是bind&lt;void&gt;。由于这是两种不同的类型,您不能将它们放在一个队列中。让logout 返回bool(即使它总是返回true 或其他东西)将是解决此问题的一种(可能相对轻松)的方法。

      tl;dr:将logout 更改为返回bool,然后将您的队列声明为deque&lt; bind&lt;bool&gt; &gt;

      编辑:考虑到许多类型,我建议您为自己创建某种特殊的容器类。像这样的:

      class EnqueuedFunc
      {
          virtual void operator()() = 0;
      };
      
      class LoginFunc : public EnqueuedFunc
      {
          bind<bool> func;
      
          LoginFunc(bind<bool> fn)
          {
              func = fn;
          }
          void operator()()
          {
              fn();
          }
      };
      
      class LogoutFunc : public EnqueuedFunc
      {
          bind<void> func;
      
          LoginFunc(bind<void> fn)
          {
              func = fn;
          }
          void operator()()
          {
              fn();
          }
      };
      

      然后你的队列是deque&lt;EnqueuedFunc&gt;

      【讨论】:

      • 对不起应该更清楚。 login() 和 logout() 只是示例。还有许多其他函数,需要处理不同的参数和不同的返回类型。所以你的建议是不可行的。
      • @Beta:啊哈,好吧。我相信我的编辑可能会对您有所帮助,但我不得不承认我对 bind 的经验不够,无法确定这会按预期工作。
      • 谢谢!这真的很接近我必须做的事情,而 J. Calleja 的解决方案是正确的。
      最近更新 更多