首页 > 解决方案 > C++ 是否可以实现指向不同参数列表的函数指针?

问题描述

我最近写了关于类成员函数回调的功能。我需要保存回调对象和函数指针,然后调用函数指针并在需要回调的地方填写适当的参数。

我一开始是typedef void (AAA::*Function)(int a, int b);.

class AAA
{
public:
    int add(int a, int b)
    {
        return (a + b);
    }
};

class BBB
{
public:

    void setValue(std::string value)
    {
        this->value = value;
    }

private:
    std::string value;
};

class CCC
{
public:

    void bind(??? p)    // Binding objects and callback functions.
    {
        this->p = p;
    }

    template <class... Args>
    auto callback(Args&&... args)   // Autofill parameter list.
    {
        return this->p(std::forward<Args>(args)...);
    }

private:
    ??? p;  // How is this function pointer implemented?
};

int main()
{
    AAA aaa;
    BBB bbb;

    CCC ccc;
    ccc.bind(???(aaa, &AAA::add));
    int number = ccc.callback(5, 6);

    ccc.bind(???(bbb, &BBB::setValue));
    ccc.callback("Hello");

    system("pause");
    return 0;
}

我不知道如何实现函数指针“???”。

标签: c++c++11visual-c++c++14c++17

解决方案


您基本上要求具有完全动态类型和检查的函数调用。

要进行完全动态的函数调用,您基本上必须抛弃 C++ 函数调用系统。

这是一个坏主意,但我会告诉你如何去做。

动态可调用对象大致如下所示:

using dynamic_function = std::function< std::any( std::vector<std::any> ) >

在哪里使用使用

struct nothing_t {};

当我们想要返回时void

然后你编写机器,获取一个对象和一个特定的签名,并将其包装起来。

template<class R, class...Args, class F>
struct dynamic_function_maker {
  template<std::size_t...Is>
  dynamic_function operator()(std::index_sequence<Is...>, F&& f)const {
    return [f=std::forward<F>(f)](std::vector<std::any> args)->std::any {
      if (sizeof...(Is) != args.size())
        throw std::invalid_argument("Wrong number of arguments");
      if constexpr( std::is_same< std::invoke_result_t<F const&, Args... >, void >{} )
      {
        f( std::any_cast<Args>(args[Is])... );
        return nothing_t{};
      }
      else
      {
        return f( std::any_cast<Args>(args[Is])... );
      }
    };
  }
  dynamic_function operator()(F&& f)const {
    return (*this)(std::make_index_sequence<sizeof...(Args)>{}, std::forward<F>(f));
  }
};
template<class R, class...Args, class F>
dynamic_function make_dynamic_function(F f){
  return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}

接下来,您将要推断函数指针的签名等:

template<class R, class...Args>
dynamic_function make_dynamic_function(R(*f)(Args...)){
  return dynamic_function_maker<R,Args...,F>{}(std::forward<F>(f));
}
template<class Tclass R, class...Args>
dynamic_function make_dynamic_function(T* t, R(T::*f)(Args...)){
  return dynamic_function_maker<R,Args...,F>{}(
    [t,f](auto&&...args)->decltype(auto){return (t->*f)(decltype(args)(args)...);}
  );
}

那么在修复上面的错别字之后,你应该能够解决你原来的问题。

再次,作为一个真正可以编写和理解上述代码的人,我强烈建议你不要使用它。它脆弱而危险。

几乎没有充分的理由将回调存储在您不知道要使用什么参数调用它的地方。

CCC对于您要调用它的每组参数,应该有不同的类型和实例。当人们问这个问题时,有 99/100 次他们问错了问题。


推荐阅读