如何使用推导的签名生成成员函数

时间:2013-08-20 08:03:28

标签: c++ metaprogramming template-meta-programming

是否可以产生方法定义(具有确切数量的参数和已知类型的返回值),具有:

  • 可变参数包中的方法参数类型“冻结”
  • 推导出的方法返回类型
  • 方法名称(传递给宏?)

详细说明:

我有一个简单的反射结构(省略了可读性的部分特化),它推导出成员函数的返回类型和参数类型:

template<typename RetType, typename ...ArgTypes>
struct reflect_method<RetType(HostClassType::*)(ArgTypes...)> {
  using method_type = RetType;
  using method_args = type_placeholder<ArgTypes...>;
  using call_type = RetType(HostClassType::*)(ArgTypes...);
};

其中method_type是方法返回类型,method_args是辅助模板struct type_placeholder中“冻结”的方法参数类型。

我要做的是在生成的类中创建一个方法,该方法将反映其他类的另一个方法的参数和返回类型。创建的方法将为反射方法提供装饰。

伪代码实现:

#define RPCCLASS(class_name)    class RPC##class_name : public class_name   \
                                {                                           \
                                  using SelfType = RPC##class_name;         \
                                  using ParentType = class_name;

#define RPCCLASS_END()          };




#define RPCBIND(method_name)   \
    using method_name_##tag = reflect_method<decltype(ParentType::method_name)>; \
    method_name_##tag::method_type
    method_name(method_name_##tag::method_args::at<0>::type arg0, \
                method_name_##tag::method_args::at<1>::type arg1, \
                /* ... */                                         \
                /*don't know how to put correct number of arguments here)*/)    \
    {                                                                           \
      /* do some stuff */                                                       \
      /* ... */                                                                 \
      /* invoke the reflected method */                                         \
      return Invoke<method_name_##tag>::apply(this, method_name,                \
                                              arg0,                             \
                                              arg1                              \
             /*again don't know how to put correct number of arguments here)*/) \
     }


 // USAGE:
 class MyOwnClass {
 public:
   virtual long long doFun(int a, char b, const std::string& c);
 };


 RPCCLASS(MyOwnClass)
   RPCBIND(doFun)
 RPCCLASS_END()

1 个答案:

答案 0 :(得分:2)

我找到了解决方案。我没有尝试生成成员函数以反映装饰方法,而是想出我可以生成成员函数。仿函数被实现为具有operator()(...)的模板结构。这允许我在保留成员函数调用语义的同时具有正确数量的参数的特化。

示例代码:

template <int Count>
struct apply_placeholders
{
};

template <>
struct apply_placeholders<1>
{
  template<typename CallType, typename Self, template<typename>class CallPtrType>
  static CallType apply(Self* self, CallPtrType<Self> callPtr)
  {
    return std::bind(std::mem_fn(callPtr), self, std::placeholders::_1);
  }
};
template <>
struct apply_placeholders<2>
{
  template<typename CallType, typename Self, template<typename>class CallPtrType>
  static CallType apply(Self* self, CallPtrType<Self> callPtr)
  {
    return std::bind(std::mem_fn(callPtr), self, std::placeholders::_1, std::placeholders::_2);
  }
};
template <>
struct apply_placeholders<3>
{
  template<typename CallType, typename Self, template<typename>class CallPtrType>
  static CallType apply(Self* self, CallPtrType<Self> callPtr)
  {
    return std::bind(std::mem_fn(callPtr), self, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
  }
};
template <>
struct apply_placeholders<4>
{
  template<typename CallType, typename Self, template<typename>class CallPtrType>
  static CallType apply(Self* self, CallPtrType<Self> callPtr)
  {
    return std::bind(std::mem_fn(callPtr), self, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
  }
};

template<typename RetType, template<typename...>class FrozenArgTypes, typename... ArgTypes>
struct mimic_functor_impl
{
};

template<typename RetType, typename... ArgTypes>
struct mimic_functor_impl<RetType, type_placeholder, type_placeholder<ArgTypes...>>
{
public:
  using CallType = std::function<RetType(ArgTypes...)>;
  template<typename Self>
  using CallPtrType = RetType(Self::*)(ArgTypes...);
private:
  CallType    mCall;

public:
  mimic_functor_impl(CallType call) : mCall{call}
  {
  }

  RetType operator () (ArgTypes... args)
  {
    return mCall(args...);
  }

  template<typename Self>
  static CallType make_function(Self* self, CallPtrType<Self> callPtr)
  {
    // manually specialise the template method because the compiler get's lost on matching "Self::*" in CallPtrType
    return apply_placeholders<sizeof...(ArgTypes)>::template apply<CallType, Self, CallPtrType>(self, callPtr);
  }
};

template<typename... ArgTypes>
struct mimic_functor_impl<void, type_placeholder, type_placeholder<ArgTypes...>>
{
public:
  using CallType = std::function<void(ArgTypes...)>;
  template<typename Self>
  using CallPtrType = void(Self::*)(ArgTypes...);
private:
  CallType        mCall;

public:
  mimic_functor_impl(CallType call) : mCall{call}
  {
  }

  void operator () (ArgTypes... args)
  {
    mCall(args...);
  }
  template<typename Self>
  static CallType make_function(Self* self, CallPtrType<Self> callPtr)
  {
    // manually specialise the template method because the compiler get's lost on matching "Self::*" in CallPtrType
    return apply_placeholders<sizeof...(ArgTypes)>::template apply<CallType, Self, CallPtrType>(self, callPtr);
  }
};

template<typename Reflect>
struct mimic_functor : mimic_functor_impl<typename Reflect::method_type, type_placeholder, typename Reflect::method_args>
{
private:
  using BaseType = mimic_functor_impl<typename Reflect::method_type, type_placeholder, typename Reflect::method_args>;
public:
  mimic_functor(typename BaseType::CallType call) : BaseType(call)
  {
  }
};



#define __TAG(x)     x ## _tag

#define RPCBIND(method_name) \  
        public: \
        using __TAG(method_name) = reflect_method<decltype(&ParentType::method_name)>; \
        mimic_functor<__TAG(method_name)> method_name{mimic_functor<__TAG(method_name)>::make_function(dynamic_cast<ParentType*>( const_cast<SelfType*>( this ) ), &ParentType::method_name)};

其余代码与问题列表中的内容类似。

apply_placeholders模板扩展了所需数量的占位符,以匹配可变参数包中的参数计数。

mimic_functor_implmimic_functor模板创建了functor,其operator()(...)将与反射的方法签名匹配。仿函数在调用时也会调用反射方法。

make_function成员模板函数创建一个绑定的std :: function,其中包含带有“this”指针的反射方法。