C++ 如何将任何类的任意成员函数传递给模板以解析其签名?

C++ 如何将任何类的任意成员函数传递给模板以解析其签名?,c++,templates,c++11,variadic-templates,function-signature,C++,Templates,C++11,Variadic Templates,Function Signature,在我的引擎中,我有一个简单的反射系统,在编译时填充了类信息(也就是说,围绕一组模板构建,这使我能够自动化生成元信息的过程) 考虑以下示例: class Type { //... Map<PropertyHash, TypeProperty> _properties; }; 类类型 { //... 地图属性; }; 每种类型都有一个函数: template <class T> void InitializeType(TypeInitializer* typeIn

在我的引擎中,我有一个简单的反射系统,在编译时填充了类信息(也就是说,围绕一组模板构建,这使我能够自动化生成元信息的过程)

考虑以下示例:

class Type
{
  //...
  Map<PropertyHash, TypeProperty> _properties;
};
类类型
{
//...
地图属性;
};
每种类型都有一个函数:

template <class T>
void InitializeType(TypeInitializer* typeInitializer);
模板
void InitializeType(类型初始值设定项*类型初始值设定项);
负责类型初始化。TypeInitializer几乎没有用于向类型添加字段和基类型的方法。所以基本上,每一个新类型只需要这个函数的特殊化。稍后,当第一次查询类型时,TypeDatabase创建具体的类型对象并为其调用InitializeType()(TypeInitializer在构造过程中获取指向类型的指针)。例如:

struct CST
{
    const float* fptr;
    volatile Uint32 vuint;
    void** vptr;
};

template <>
SvrInline void InitializeType<CST>(TypeInitializer* typeInitializer)
{
    typeInitializer->AddProperty("fptr", &CST::fptr);
    typeInitializer->AddProperty("vuint", &CST::vuint);
    typeInitializer->AddProperty("vptr", &CST::vptr);
}
struct-CST
{
常量浮点*fptr;
挥发性Uint32 vuint;
无效**vptr;
};
模板
SvrInline void InitializeType(类型初始值设定项*类型初始值设定项)
{
类型初始值设定项->添加属性(“fptr”、&CST::fptr);
typeInitializer->AddProperty(“vuint”、&CST::vuint);
typeInitializer->AddProperty(“vptr”、&CST::vptr);
}
就这样。所有魔术都在TypeProperty构造函数中完成,该构造函数声明为:

template <class Object_type, class Property_type>
TypeProperty(const char* fieldName, Property_type (Object_type::* propertyPtr));
模板
TypeProperty(常量字符*字段名,属性类型(对象类型::*propertyPtr));
这使我能够知道财产的确切类型。我测试它的大小、常数、易失性等,并将此信息保存在TypeProperty对象中。很好

现在,我还需要一些与成员功能相同的东西。”“等同”的意思是,我可以像现在添加属性一样添加函数

我的第一个想法是可变模板(我的引擎是在充分支持C++11特性的情况下构建的):

模板
TypeMethod(const char*methodName,Return_t(Object_t::*)(Args&&…Args)
{
//现在怎么办?
}
但是,我不知道如何从args中提取类型。我看过一篇文章,其中介绍了一种使用函数重载的方法:

template <typename P, typename R, typename Arg1, typename... Args>
void Func(R (P::*)(Arg1 arg1, Args&&... args))
{
}

template <typename P, typename R, typename... Args>
void Func(R (P::*)(Args&&... args))
{
}

template <typename P, typename R>
void Func(R (P::*)())
{
}
模板
void Func(R(P::*)(Arg1 Arg1,Args&…Args))
{
}
模板
void Func(R(P::*)(Args&&…Args))
{
}
模板
无效函数(R(P::*)())
{
}
函数被递归地“转发”(我知道这不是一个实际的递归),每次只减少一个参数。但是,我不知道这怎么适合我的情况。

。。。
...

template <typename P, typename R, typename Arg1, typename Arg2>
void Func(R (P::*)(Arg1 arg1, Arg2 arg2))
{
    // function type is R (P::*)(Arg1 arg1, Arg2 arg2)
}

template <typename P, typename R, typename Arg1>
void Func(R (P::*)(Arg1 arg1))
{
    // function type is R (P::*)(Arg1 arg1)
}

template <typename P, typename R>
void Func(R (P::*)())
{
     // function type is R (P::*)()
}
模板 无效函数(R(P::*)(Arg1 Arg1,Arg2 Arg2)) { //函数类型为R(P::*)(Arg1 Arg1,Arg2 Arg2) } 模板 无效函数(R(P::*)(Arg1 Arg1)) { //函数类型为R(P::*)(Arg1 Arg1) } 模板 无效函数(R(P::*)()) { //函数类型为R(P::*)() }
我不熟悉可变参数。这是C++11之前的唯一解决方案。但现在C++11的新功能可能会更优雅地解决这个问题


顺便说一句,首先我在boost.pyton库实现中看到了这种解析签名的方法。

不需要递归,只需使用包扩展:

template <typename Object_t, typename Return_t, typename... Args>
TypeMethod(const char* methodName, Return_t (Object_t::*)(Args&&... args)
{
  setName(methodName);
  setObjectType<Object_t>();
  setReturnType<Return_t>();
  auto dummy[] = {0, (addArgumentType<Args>(), 0)...};
}
模板
TypeMethod(const char*methodName,Return_t(Object_t::*)(Args&&…Args)
{
setName(methodName);
setObjectType();
setReturnType();
自动虚拟[]={0,(addArgumentType(),0)…};
}

我们将包扩展放在带括号的init列表中,以确保对
addArgumentType
的调用顺序正确。

使用
decompose\u mem\u fun\u ptr
from


当没有参数时,您应该在
dummy
中至少添加1个元素。我喜欢这个解决方案。但是,我猜不出您为什么这样做:(addArgumentType(),0)。这个“0”是什么意思?dummy[]中的元素类型是什么?我也很好奇,如果传递没有参数的函数,这是否会起作用。@MateuszGrzejek:
(addArgumentType(),0).
使用逗号运算符调用
addArgumentType()
并计算为
0
进行扩展。您只需使用
{0,(addArgumentType(),0).}
来支持0参数。
自动
int
。我读得不够仔细:)已经解决了这个问题。我修改了此方法来存储有关解析参数的信息。如果提供了额外的ctor专门化,则不需要额外的“标记”。虽然所有答案都非常有用,但这一个完全符合我的编程风格。@MateuszGrzejek您必须使用doubl提供重载电子省略号(
)。请参阅中的,也可能会有所帮助。感谢您提供的这一非常有用的资源!
template <typename Object_t, typename Return_t, typename... Args>
TypeMethod(const char* methodName, Return_t (Object_t::*)(Args&&... args)
{
  setName(methodName);
  setObjectType<Object_t>();
  setReturnType<Return_t>();
  auto dummy[] = {0, (addArgumentType<Args>(), 0)...};
}
template <typename M>
TypeMethod(const char* methodName, M&m)
{
    setName(methodName);
    setObjectType<typename decompose_mem_fun_ptr<M>::class_type>();
    setReturnType<typename decompose_mem_fun_ptr<M>::return_type>();

    // use other info from decompose_mem_fun_ptr<M>.

    using args_type = typename decompose_mem_fun_ptr<M>::arguments; 

    internal_setArgs<args_type>(make_index_sequence<std::tuple_size<args_type>::value>());
}

template<typename Tuple, std::size_t...Is>
void internal_setArgs(index_sequence<Is...>)
{
    // Assuming setArg<T>(i_th).
    int dummy[] = {0, (setArg<typename std::tuple_element<Is, Tuple>::type>(Is), 0)...};
    static_cast<void>(dummy); // silent warning about unused variable.
}
#if 1 // Not in C++11
#include <cstdint>

template <std::size_t ...> struct index_sequence {};

template <std::size_t N, std::size_t ...Is>
struct make_index_sequence : make_index_sequence < N - 1, N - 1, Is... > {};

template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};

#endif // make_index_sequence