【问题标题】:How to generate a member function with a deduced signature如何生成具有推导签名的成员函数
【发布时间】:2013-08-22 04:47:17
【问题描述】:

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

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

详情:

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

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 是在帮助程序模板结构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()

【问题讨论】:

  • 你可能想看看Turtle.Mocks模拟对象框架的实现。他们的 MOCK_METHOD 宏中有类似的东西
  • 谢谢,我会调查一下
  • 如果你会使用 c++11 不应该decltype 帮助你很多吗?
  • @Alex 我需要使用 C++11 :) decltype 允许您检查方法签名,我需要的是相反的。拥有一个函数签名,我想生成一个类似的函数(仅更改函数名称)。示例:从“int original(float, char)”我想得到“int producer_from_original(float, char)”

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


【解决方案1】:

我找到了解决方案。我没有尝试生成一个成员函数来反映一个修饰的方法,而是发现我可以生成一个成员函数。函子被实现为带有 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 模板创建的仿函数,其运算符 ()(...) 将匹配反射方法签名。调用函子时,也会调用反射方法。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-22
    • 2015-07-06
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-21
    相关资源
    最近更新 更多