繁体   English   中英

从指针调用可变参数模板以增强boost :: any

[英]Calling a variadic template from a pointer to boost::any

我正在尝试创建具有不同参数和返回类型的函数映射。 因此,为了做到这一点,我在stackoverflow上进行了大量搜索,我认为我得到了我所需要的,但不完全是...

背景:

这篇文章中, pmr的答案是我需要的最准确的解决方案。 因此,我已将函数调用扩展为可变参数模板(希望如此)。 因此,这是该调用的我的版本( AnyCaller类的其余部分完全相同):

   template<typename Ret, typename ...Args>
   Ret call(const std::string& s, Args&&... arg) {
     // we have to assume that our users know what we are actually returning here
     const boost::any& a = calls[s];
     return boost::any_cast< std::function<Ret(Args...)> >(a)(std::forward<Args>(arg)...);
   }

并且可以编译。 现在,这些是我用来测试该类的三个函数:

int foo() { MessageBoxW(nullptr, L"Helolo VOID", L"Info", NULL); return 1; }
double foo2(std::wstring str) { MessageBoxW(nullptr, str.data(), L"Info", NULL); return double(4.5); }

UINT foo3(std::wstring str1, std::wstring str2) 
{ 
  std::wstring strBuffer;

  strBuffer = str1;
  strBuffer += L"==>";
  strBuffer += str2;
  MessageBoxW(nullptr, strBuffer.data(), L"Info", NULL); 

  return 4; 
}

因此,第一个具有int(void)的签名,第二个double(std :: wstring)和第三个double(std :: wstring,std :: wstring)的签名。

现在,这是测试代码:

  AnyCaller c;
  c.add("foo1", std::function<int(void)>(foo));
  c.add("foo2", std::function<double(std::wstring)>(foo2));
  c.add("foo3", std::function<UINT(std::wstring, std::wstring)>(foo3));

  c.call<int>("foo1");
  c.call<double, std::wstring>("foo2", std::wstring(L"foo2!!!").data());
  c.call<UINT, std::wstring, std::wstring>("foo3", std::wstring(L"foo3!!!").data(), std::wstring(L"---foo3!!!").data());

一切运行顺利:)

因此,这还可以,我真正需要的是添加对函数成员的支持。 基本上,我要做的是创建一个具有完全相同的三个功能的A类,还有一些用于测试目的:

class A
{
public:
  int foo() { MessageBoxW(nullptr, L"Helolo VOID", L"Info", NULL); return 1; }
  double foo2(std::wstring str) { MessageBoxW(nullptr, str.data(), L"Info", NULL); return double(4.5); }

  UINT foo3(std::wstring str1, std::wstring str2)
  {
    std::wstring strBuffer;

    strBuffer = str1;
    strBuffer += L"==>";
    strBuffer += str2;
    MessageBoxW(nullptr, strBuffer.data(), L"Info", NULL);

    return 4;
  }

  std::wstring foo4(VOID) { return std::wstring(L"foo4"); }
  std::wstring foo5(std::wstring strData) { return (strData + L"--foo5"); }
  VOID foo6(VOID) { ; }
};

但是我无法使它正常工作。 我的第一个问题是将指针添加到成员函数:

A a;
c.add("foo1", std::function<int(void)>(&A::foo)); // => Not valid
c.add("foo1", std::function<int(void)>(&a.foo));  // => Not valid
c.add("foo1", &a.foo);                            // => Not valid
c.add("foo1", a.foo);                             // => Not valid
c.add("foo1", ?????); //What in heaven goes here?

显然,一定是某种转换的,但我无法想象...

当然,在那之后,我需要进行实际的调用:

int nRet = c.call<int>("foo1");

感谢任何可以帮助您的人:_)

PS:我不能做静态成员,如果那是一个解决方案...

PS2:我正在使用VS2013 ...

解:

感谢@ Kiroxas,@ Praetorian和本文的评论,我提出了不涉及可变参数模板的解决方案。

这是我的测试班AB

class A
{
public:
  int foo1() { MessageBoxW(nullptr, L"Helolo VOID", L"Info", NULL); return 1; }
  int foo2(std::wstring str) { MessageBoxW(nullptr, str.data(), L"Info", NULL); return 5; }

  int foo3(std::wstring str1, std::wstring str2)
  {
    std::wstring strBuffer;

    strBuffer = str1;
    strBuffer += L"==>";
    strBuffer += str2;
    MessageBoxW(nullptr, strBuffer.data(), L"Info", NULL);

    return 4;
  }
};

class B
{
public:
  std::wstring foo4(VOID) { return std::wstring(L"foo4"); }
  std::wstring foo5(std::wstring strData) { return (strData + L"--foo5"); }
  VOID foo6(VOID) { ; }
  double foo7(std::wstring str1, int nNum) 
  {
    std::wstring strBuffer;

    strBuffer = str1;
    strBuffer += L"==>";
    strBuffer += std::to_wstring(nNum);
    MessageBoxW(nullptr, strBuffer.data(), L"Info", NULL);

    return double(3.1415);
  }
};

这是将它们插入到数组中并调用它们的代码:)我的理想解决方案是将它们插入到地图中,因此,一旦我全部工作,我将再次进行更新! 该职位。

      typedef struct
      {
        UINT ID;
        std::wstring NAME;
        boost::any Func;
      } funcs;
      funcs CallBackItems[] =
      {
        //From class A
        { 0, L"foo1", std::function<int(void)>(std::bind(&A::foo1, a)) },
        { 1, L"foo2", std::function<int(std::wstring)>(std::bind(&A::foo2, a, std::placeholders::_1)) },
        { 2, L"foo3", std::function<int(std::wstring, std::wstring)>(std::bind(&A::foo3, a, std::placeholders::_1, std::placeholders::_2)) },
        //From class B
        { 3, L"foo4", std::function<std::wstring(void)>(std::bind(&B::foo4, b)) },
        { 4, L"foo5", std::function<std::wstring(std::wstring)>(std::bind(&B::foo5, b, std::placeholders::_1)) },
        { 5, L"foo6", std::function<void(void)>(std::bind(&B::foo6, b)) },
        { 6, L"foo7", std::function<double(std::wstring, int)>(std::bind(&B::foo7, b, std::placeholders::_1, std::placeholders::_2)) }
      };

      int nResult = -1;
      std::wstring wstrResult = L"";
      double dResult = 0.0;

  //class A
  nResult = boost::any_cast<std::function<int(void)>>(CallBackItems[0].Func)();
  nResult = boost::any_cast<std::function<int(std::wstring)>>(CallBackItems[1].Func)(L"foo2");
  nResult = boost::any_cast<std::function<int(std::wstring, std::wstring)>>(CallBackItems[2].Func)(L"foo", L"3");
  //class B
  wstrResult = boost::any_cast<std::function<std::wstring(void)>>(CallBackItems[3].Func)();
  wstrResult = boost::any_cast<std::function<std::wstring(std::wstring)>>(CallBackItems[4].Func)(L"foo5");
  boost::any_cast<std::function<void(void)>>(CallBackItems[5].Func)();
  dResult = boost::any_cast<std::function<double(std::wstring, int)>>(CallBackItems[6].Func)(L"foo", 7);

A::foo(1|2|3)是非静态的成员函数,这意味着它们采用隐式的第一个参数,即在其上被调用的对象实例的指针( this指针)。 您有两个可用的选项,或者使用std::bind要在其上调用成员函数的对象,或者稍后在call()该对象时将指针传递给该对象。

我用一个可变参数模板版本替换了您的两个call超载

template<typename Ret, typename... T>
Ret call(const std::string& s, T&&... arg) {
    // we have to assume that our users know what we are actually returning here
    const boost::any& a = calls[s];
    return boost::any_cast< std::function<Ret(T...)> >(a)(std::forward<T>(arg)...);
}

选项1:使用std::bind

A a;
AnyCaller c;
c.add("foo1", std::function<int()>(std::bind(&A::foo1, &a)));
c.add("foo2", std::function<double(std::wstring)>(
                std::bind(&A::foo2, &a, std::placeholders::_1)));

c.call<int>("foo1");
c.call<double>("foo2", std::wstring(L"Calling foo2"));

选项2:在调用函数时传递对象指针。 请注意,在这种情况下, std::function的类型是不同的。

A a;
AnyCaller c;
c.add("foo1", std::function<int(A*)>(&A::foo1));
c.add("foo2", std::function<double(A*, std::wstring)>(&A::foo2));

c.call<int>("foo1", &a);
c.call<double>("foo2", &a, std::wstring(L"Calling foo2"));

第二个选项不起作用在VS2013。

两种选项的现场演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM