首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模拟std::功能功能

模拟std::功能功能
EN

Stack Overflow用户
提问于 2022-01-14 05:45:33
回答 2查看 109关注 0票数 0

我试图在下面模拟std::function功能,但我遇到了以下错误

代码语言:javascript
复制
class Player
{
public:
void move_to(Point location);
};
std::function<void(Player&, Point)> fun = &Player::move_to;
Player hero;
fun(hero, point{ 2, 4 });
代码语言:javascript
复制
fp.cc:32:33: error: variable ‘fun<void(Player&, Point)> f’ has initializer but incomplete type
   32 |    fun<void(Player &, Point p)> f = &Player::move_to;
代码语言:javascript
复制
#include <iostream>

using namespace std;
template <typename T>
struct fun;

template <typename Ret, typename T, typename ...Args>
struct fun <Ret(*)(T&, Args...)>{
   char *data;
   using fptr = Ret(T::*)(Args...);
   fun(fptr p) : data(p) {}
   Ret operator()(T &t, Args... args) {
      if (std::is_same_v<Ret, void>) {
         (t.*((fptr)data))(args...);
      }
      return (t.*((fptr)data))(args...); 
   }
};

struct Point {
   int x;
   int y;
};

struct Player {
   void move_to(Point p) {
      cout << __PRETTY_FUNCTION__ << endl;
   }
};

int main() {
   fun<void(Player &, Point p)> f = &Player::move_to;
   Point p{1,2};
   Player pl;
//   f(pl, p);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-15 18:14:32

代码语言:javascript
复制
struct unused_t {};
// can store any of a function pointer, member function pointer, or other
// pointer.  It is a bit annoying, and not complete even.
union state_t {
  void(unused_t::*pm)();
  void(*pf)();
  void*pv;
  state_t():pv(nullptr){}
  template<class R0, class...A0s>
  state_t(R0(*f)(A0s...)):pf(reinterpret_cast<void(*)()>(f)) {}
  template<class X, class R0, class...A0s>
  state_t(R0(X::*f)(A0s...)):pm(reinterpret_cast<void(unused_t::*)()>(f)) {}
  template<class X, class R0, class...A0s>
  state_t(R0(X::*f)(A0s...) const):pm(reinterpret_cast<void(unused_t::*)()>(f)) {}
  // add in & and && overloads of member function pointers here

  template<class T>
  state_t(T* p):pv((void*)p) {}
};
template<class Sig>
struct fun;

template <class R, class...As>
struct fun <R(As...)>{
  using pf_t = R(*)(state_t, As&&...);

  state_t state;
  pf_t pf = nullptr;

  fun() = default;
  explicit operator bool() const { return pf; }
  template<class R0, class...A0s>
  fun( R0(*f)(A0s...) ):
    state(f),
    pf([](state_t state, As&&...as)->R{
      auto f = (R0(*)(A0s...))(state.pf);
      return std::invoke( f, std::forward<As>(as)... );
    })
  {}
  template<class T, class R0, class...A0s>
  fun( R0(T::*f)(A0s...) ):
    state(f),
    pf([](state_t state, As&&...as)->R{
      auto f = (R0(T::*)(A0s...))(state.pm);
      return std::invoke( f, std::forward<As>(as)... );
    })
  {}
  template<class T, class R0, class...A0s>
  fun( R0(T::*f)(A0s...) const ):
    state(f),
    pf([](state_t state, As&&...as)->R{
      auto f = (R0(T::*)(A0s...) const)(state.pm);
      return std::invoke( f, std::forward<As>(as)... );
    })
  {}
  R operator()(As... args) const {
    return pf( state, std::forward<As>(args)... );
  }
};

这确实使用了std::invoke

测试代码:

代码语言:javascript
复制
struct bob {
  int foo() const { return 3; };
};
int main() {
  fun<int(bob&)> f = &bob::foo;
  bob b;
  std::cout << f(b);
}

实例化

下面是一个c++20版本:

代码语言:javascript
复制
struct unused_t {};
// can store any of a function pointer, member function pointer, or other
// pointer.  It is a bit annoying, and not complete even.
union state_t {
  void(unused_t::*pm)();
  void(*pf)();
  void*pv;
  state_t():pv(nullptr){}
  template<class R0, class...A0s>
  state_t(R0(*f)(A0s...)):pf(reinterpret_cast<void(*)()>(f)) {}
  template<class X, class R0, class...A0s>
  state_t(R0(X::*f)(A0s...)):pm(reinterpret_cast<void(unused_t::*)()>(f)) {}
  template<class X, class R0, class...A0s>
  state_t(R0(X::*f)(A0s...) const):pm(reinterpret_cast<void(unused_t::*)()>(f)) {}
  // add in & and && overloads of member function pointers here

  template<class T>struct tag_t {};
  template<class T>using type_t = T;

  template<class R, class...As>
  type_t<R(*)(As...)> extract( tag_t<R(*)(As...)>) const {
    return (R(*)(As...))pf;
  }
  template<class T, class R, class...As>
  type_t<R(T::*)(As...)> extract( tag_t<R(T::*)(As...)>) const {
    return (R(T::*)(As...))pm;
  }
  template<class T, class R, class...As>
  type_t<R(T::*)(As...) const> extract( tag_t<R(T::*)(As...) const>) const {
    return (R(T::*)(As...) const)pm;
  }
  template<class T>
  type_t<T*> extract( tag_t<T*>) const {
    return (T*)pv;
  }
  template<class T>
  state_t(T* p):pv((void*)p) {}
};
template<class Sig>
struct fun;

template <class R, class...As>
struct fun <R(As...)>{
  using pf_t = R(*)(state_t, As&&...);

  state_t state;
  pf_t pf = nullptr;

  fun() = default;
  explicit operator bool() const { return pf; }
  template<std::invocable<As...> F>
  requires std::is_convertible_v< std::invoke_result_t<F, As...>, R >
  fun( F f ):
    state(std::forward<F>(f)),
    pf([](state_t state, As&&...as)->R{
      auto f = state.extract(state_t::tag_t<F>{});
      return std::invoke( f, std::forward<As>(as)... );
    })
  {}
  R operator()(As... args) const {
    return pf( state, std::forward<As>(args)... );
  }
};

烦人的部分是以统一的方式存储指向成员函数、指针或函数指针的指针。C++标准指出,这3种类型的指针不能保证兼容。

因此,state_t类型可以将3种类型中的任何一种存储在一个联合中,但是有一堆样板可以统一地对待它们。

票数 1
EN

Stack Overflow用户

发布于 2022-01-14 06:00:07

您的代码已接近,但有几个小错误:

  • 您只为fun提供了Ret(*)(T&, Args...)的定义,但fun<void(Player &, Point p)>与此模板不匹配。因此,我删除了(*),这在您的专门化中并不是真正需要的。
  • 函数指针不能转换为/来自char *,因此我将data的类型更改为fptr,以便与参数类型匹配。

螺栓连接

代码语言:javascript
复制
#include <iostream>

using namespace std;
template <typename T>
struct fun;

template <typename Ret, typename T, typename ...Args>
struct fun <Ret(T&, Args...)>{
   using fptr = Ret(T::*)(Args...);
   fptr data;
   fun(fptr p) : data(p) {}
   Ret operator()(T &t, Args... args) {
      if (std::is_same_v<Ret, void>) {
         (t.*((fptr)data))(args...);
      }
      return (t.*((fptr)data))(args...); 
   }
};

struct Point {
   int x;
   int y;
};

struct Player {
   void move_to(Point p) {
      cout << __PRETTY_FUNCTION__ << endl;
   }
};

int main() {
   fun<void(Player &, Point p)> f = &Player::move_to;
   Point p{1,2};
   Player pl;
   f(pl, p);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70706473

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档