带有不同参数的C++ std :: function变量

Mar*_*rry 12 c++ c++11

在我的回调系统中,我想std::function用不同的参数存储(或其他东西).

例:

  1. 我想打电话 void()
  2. 我想打电话 void(int, int)

我希望1)和2)存储在同一个变量中,并选择在执行调用中调用的内容

FunctionPointer f0;
FunctionPointer f2;

f0();
f2(4, 5);
Run Code Online (Sandbox Code Playgroud)

可以这样做吗?或者我必须根据输入参数计数创建几个"FuntionPointer"模板.

编辑

有可能以某种方式利用std :: bind来完成这项任务吗?使用std :: bind我可以拥有std::function<void()> f = std::bind(test, 2, 5);

编辑2

实际用例:我有一个触发系统,我想为动作分配功能指针,所以当动作发生时,调用函数.伪码样本:

structure Trigger 
{
   Function f;
}

Init:
  Trigger0.f = pointer to some function ()
  Trigger1.f = pointer to some function (a, b)

Input: 
  Find Trigger by input
  if (in == A) Trigger.f();
  else Trigger.f(10, 20)
Run Code Online (Sandbox Code Playgroud)

或者如果可能的话

Input:
  Find Trigger by input
  if (in == A) f = bind(Trigger.f);
  else f = bind(Trigger.f, 10, 20);
  f()
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 11

std::function<void()>并且std::function<void(int, int)>是两种绝对不同的类型.您需要某种联合功能(或多态)来存储未知类型的对象.

如果您可以使用Boost,您可以轻松地执行以下操作boost::variant:

// Declaration:
boost::variant<std::function<void()>, std::function<void(int, int)> > f;

// Calling, explicit:
if (fContainsNullary()) {
  boost::get<std::function<void()>>(f)();
} else {
  boost::get<std::function<void(int, int)>>(f)(4, 5);
}
Run Code Online (Sandbox Code Playgroud)

由你来提供逻辑fContainsNullary().或者,您可以使用访问者使用变体自己存储的值类型知识:

struct MyVisitor : boost::static_visitor<void>
{
  result_type operator() (const std::function<void()> &a) {
    a();
  }

  result_type operator() (const std::function<void(int, int)> &a) {
    a(4, 5);
  }
};

// Calling, via visitor:
boost::apply_visitor(MyVisitor(), f);
Run Code Online (Sandbox Code Playgroud)

如果Boost不是一个选项,你可以手工制作一个适合union的目的.


And*_*nov 5

以下解决方案可能对您有用(我不确定此处的代码是否绝对正确):

std::function使用虚拟析构函数创建包装器以启用动态转换

class function_wrapper_base
{
    virtual ~function_wrapper_base();
}

template <class... Args>
class function_wrapper
    : public function_wrapper_base
{
public:
   std::function<void, Args...> f;
   ...
};
Run Code Online (Sandbox Code Playgroud)

然后创建一个类 variant_function_holder

class variant_function_holder
{
    std::unique_ptr<function_wrapper_base> f;
    ...
    template <class... Args>
    void operator()(Args&&... args)
    {
        function_wrapper<std::decay<Args>::type...> * g = dynamic_cast<function_wrapper<std::decay<Args>::type...>>(f.get());

        if (g == nullptr)
        {
            // ToDo
        }

        g->f(std::forward<Args>(args)...);
    }
};
Run Code Online (Sandbox Code Playgroud)


jnb*_*mez 4

好吧,如果你可以使用RTTI,你可以MultiFuncObject像这样定义一个,并且你可以轻松绑定其他函数。此外,您还可以轻松地致电他们。但不幸的是,这种方法只适用于有限数量的参数。但实际上boost::bind也支持有限数量的参数(默认为 9 个)。因此您可以扩展此类来满足您的需求。

在向您提供 的来源之前MultiFuncObject,我想向您展示如何使用它。它需要一个模板参数作为返回类型。您可以将新函数与+=运算符绑定。通过一些模板魔法,该类可以区分具有相同参数数量和至少一种不同参数类型的绑定函数之间的差异。

您需要 C++11,因为MultiFuncObject使用std::unordered_mapstd::type_index

这是用法:

#include <iostream>
using namespace std;

void _1() {
  cout << "_1" << endl;
}

void _2(char x) {
  cout << "_2" << " " << x << endl;
}

void _3(int x) {
  cout << "_3" << " " << x << endl;
}

void _4(double x) {
  cout << "_4" << " " << x << endl;
}

void _5(int a, int b) {
  cout << "_5" << " " << a << " " << b << endl;
}

void _6(char a, int b) {
  cout << "_6" << " " << a << " " << b << endl;
}

void _7(int a, int b, int c) {
  cout << "_7" << " " << a << " " << b << " " << c << endl;
}

int main() {
  MultiFuncObject<void> funcs;
  funcs += &_1;
  funcs += &_2;
  funcs += &_3;
  funcs += &_4;
  funcs += &_5;
  funcs += &_6;
  funcs += &_7;
  funcs();
  funcs('a');
  funcs(56);
  funcs(5.5);
  funcs(2, 5);
  funcs('q', 6);
  funcs(1, 2, 3);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我希望这接近你想要的。这是以下的来源MultiFuncObject

#include <typeinfo>
#include <typeindex>
#include <unordered_map>

using namespace std;

template <typename R>
class MultiFuncObject {
  unordered_map<type_index, void (*)()> m_funcs;
public:

  MultiFuncObject<R> operator +=( R (* f)() ) {
    m_funcs[typeid( R() )] = (void (*)()) f;
    return *this;
  }

  template <typename A1>
  MultiFuncObject<R> operator +=( R (* f)(A1) ) {
    m_funcs[typeid( R(A1) )] = (void (*)()) f;
    return *this;
  }

  template <typename A1, typename A2>
  MultiFuncObject<R> operator +=( R (* f)(A1, A2) ) {
    m_funcs[typeid( R(A1, A2) )] = (void (*)()) f;
    return *this;
  }

  template <typename A1, typename A2, typename A3>
  MultiFuncObject<R> operator +=( R (* f)(A1, A2, A3) ) {
    m_funcs[typeid( R(A1, A2, A3) )] = (void (*)()) f;
    return *this;
  }

  R operator()() const
  {
    unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R() ));
    if (it != m_funcs.end()) {
      R (*f)() = ( R (*)() )(it->second);
      (*f)();
    }
  }

  template <typename A1>
  R operator()(A1 a1) const
  {
    unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R(A1) ));
    if (it != m_funcs.end()) {
      R (*f)(A1) = ( R (*)(A1) )(it->second);
      (*f)(a1);
    }
  }

  template <typename A1, typename A2>
  R operator()(A1 a1, A2 a2) const
  {
    unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R(A1, A2) ));
    if (it != m_funcs.end()) {
      R (*f)(A1, A2) = ( R (*)(A1, A2) )(it->second);
      (*f)(a1, a2);
    }
  }

  template <typename A1, typename A2, typename A3>
  R operator()(A1 a1, A2 a2, A3 a3) const
  {
    unordered_map<type_index, void (*)()>::const_iterator it = m_funcs.find(typeid( R(A1, A2, A3) ));
    if (it != m_funcs.end()) {
      R (*f)(A1, A2, A3) = ( R (*)(A1, A2, A3) )(it->second);
      (*f)(a1, a2, a3);
    }
  }

};
Run Code Online (Sandbox Code Playgroud)

std::unordered_map它使用 的键std::type_index和值存储不同的函数原型void (*)()。当需要时,使用该映射检索正确的函数。

这是工作示例

  • 我还做了一些性能测量:http://www.perry.cz/clanky/functions.html (2认同)