C ++ 0x:在std :: map中存储任何类型的std :: function [英] C++0x : Storing any type of std::function in a std::map

查看:1074
本文介绍了C ++ 0x:在std :: map中存储任何类型的std :: function的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在地图中存储一组std ::函数(在GCC 4.5下)

I'm trying to store a set of std::function in a map (under GCC 4.5)

我想获得2种类型的东西:

I'd like to get 2 kind of things :


  • 存储已传递参数的函数;那么你只需要
    调用f()

  • 存储没有参数的函数;那么你必须调用
    f(...)

我想我实现了第一个类Command和经理:

I think I achieved the first one with a class Command and a Manager :

class Command
{
  std::function<void()> f_;
  public:
    Command() {}
    Command(std::function<void()> f) : f_(f) {}

    void execute() { if(f_) f_(); }

};

class CommandManager
{
  typedef map<string, Command*> FMap;

  public :

  void add(string name, Command* cmd)
  {
     fmap1.insert(pair<string, Command*>(name, cmd));
  }

  void execute(string name)
  {
    FMap::const_iterator it = fmap1.find(name);
    if(it != fmap1.end())
    {
      Command* c = it->second;
      c->execute();
    }
  }

  private :

    FMap fmap1;

};

可以这样使用:

class Print{

   public:
   void print1(string s, string s1){ cout<<"print1 : "<<"s : "<<s<<" s1 : "<<s1<<endl; }
   int print2(){ cout<<"print2"<<endl; return 2;}

};

#include <string>
#include <functional>

int main()
{
  Print p = Print();

  function<void()> f1(bind(&Print::print1, &p, string("test1"), string("test2")));

  function<int()> f2(bind(&Print::print2, &p));

  CommandManager cmdMgr = CommandManager();
  cmdMgr.add("print1", new Command(f1));
  cmdMgr.execute("print1");

  cmdMgr.add("print2", new Command(f2));
  cmdMgr.execute("print2");

  return 0;
}

现在我想要这样做:

 int main()
 {
      Print p = Print();

      function<void(string, string)> f1(bind(&Print::print1, &p, placeholders::_1, placeholders::_2));

      CommandManager cmdMgr = CommandManager();
      cmdMgr.add("print1", new Command(f1));
      cmdMgr.execute("print1", string("test1"), string("test2"));

      return 0;
    }

有没有办法,例如使用类型擦除?

Is there a way, using type-erasure for example ?

推荐答案

您可以使用动态转换在运行时确定列表中函数的类型。
请注意,我添加了shared_ptr来删除原始示例中的内存泄漏。如果execute方法被错误的参数调用(如果dynamic_cast产生为0),也许你想抛出异常。

You could use dynamic cast to determine the type of the function in the list at runtime. Please note that I added shared_ptr to remove the memory leak in the original sample. Perhaps you want to throw a exception if the execute method is called with the wrong arguments (if the dynamic_cast yields 0).

用法:

void x() {}
void y(int ) {}
void main() {
    CommandManager m;
    m.add("print", Command<>(x));
    m.add("print1", Command<int>(y));
    m.execute("print");
    m.execute("print1", 1);
}

代码(支持可变参数模板gcc-4.5):

Code (with variadic template support for example gcc-4.5):

#include <functional>
#include <map>
#include <string>
#include <memory>

using namespace std;

class BaseCommand
{
public:
    virtual ~BaseCommand() {}
};

template <class... ArgTypes>
class Command : public BaseCommand
{
  typedef std::function<void(ArgTypes...)> FuncType;
  FuncType f_;
  public:
    Command() {}
    Command(FuncType f) : f_(f) {}
    void operator()(ArgTypes... args) { if(f_) f_(args...); }
};

class CommandManager
{
  typedef shared_ptr<BaseCommand> BaseCommandPtr;
  typedef map<string, BaseCommandPtr> FMap;
  public :

  template <class T>
  void add(string name, const T& cmd)
  {
     fmap1.insert(pair<string, BaseCommandPtr>(name, BaseCommandPtr(new T(cmd))));
  }

  template <class... ArgTypes>
  void execute(string name, ArgTypes... args)
  {
    typedef Command<ArgTypes...> CommandType;
    FMap::const_iterator it = fmap1.find(name);
    if(it != fmap1.end())
    {
      CommandType* c = dynamic_cast<CommandType*>(it->second.get());
      if(c)
      {
    (*c)(args...);
      }
    }
  } 

  private :
    FMap fmap1;
};

没有可变模板支持(示例VS2010):

without variadic template support (example VS2010):

#include <functional>
#include <map>
#include <string>
#include <memory>

using namespace std;
class Ignored;

class BaseCommand
{
public:
    virtual ~BaseCommand() = 0 {};
};

template <class A1 = Ignored>
class Command : public BaseCommand
{
  typedef std::function<void(A1)> FuncType;
  FuncType f_;
  public:
    Command() {}
    Command(FuncType f) : f_(f) {}
    void operator()(const A1& a1) { if(f_) f_(a1); }
};

template <>
class Command<Ignored> : public BaseCommand
{
  typedef std::function<void()> FuncType;
  FuncType f_;
  public:
    Command() {}
    Command(FuncType f) : f_(f) {}
    void operator()() { if(f_) f_(); }
};

class CommandManager
{
  typedef shared_ptr<BaseCommand> BaseCommandPtr;
  typedef map<string, BaseCommandPtr> FMap;
  public :

  template <class T>
  void add(string name, const T& cmd)
  {
     fmap1.insert(pair<string, BaseCommandPtr>(name, BaseCommandPtr(new T(cmd))));
  }

  template <class A1>
  void execute(string name, const A1& a1)
  {
    typedef Command<A1> CommandType;
    FMap::const_iterator it = fmap1.find(name);
    if(it != fmap1.end())
    {
      CommandType* c = dynamic_cast<CommandType*>(it->second.get());
      if(c)
      {
        (*c)(a1);
      }
    }
  } 

  void execute(string name)
  {
    typedef Command<> CommandType;
    FMap::const_iterator it = fmap1.find(name);
    if(it != fmap1.end())
    {
      CommandType* c = dynamic_cast<CommandType*>(it->second.get());
      if(c)
      {
        (*c)();
      }
    }
  }
  private :
    FMap fmap1;
};

这篇关于C ++ 0x:在std :: map中存储任何类型的std :: function的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆