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

时间:2014-02-11 13:54:59

标签: c++ templates c++11 variadic-templates function-signature

在我的引擎中,我有一个简单的反射系统,在编译时填充了类信息(即围绕模板集构建,允许我自动生成元信息的过程)。

请考虑以下示例:

class Type
{
  //...
  Map<PropertyHash, TypeProperty> _properties;
};

每种类型都有一个功能:

template <class T>
void InitializeType(TypeInitializer* typeInitializer);

负责类型初始化。 TypeInitializer几乎没有用于添加要键入的字段和基类型的方法。所以基本上,每种新类型都只需要特殊化这个功能。稍后,当第一次查询类型时,TypeDatabase会创建具体的Type对象并为其调用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);
}

就是这样。所有魔法都在TypeProperty构造函数中完成,该构造函数声明为:

template <class Object_type, class Property_type>
TypeProperty(const char* fieldName, Property_type (Object_type::* propertyPtr));

这让我知道属性的确切类型。我测试它的大小,常量,易失性等,并在TypeProperty对象中保存此信息。好的。

现在,我需要一些相同的成员函数。 '相同'意味着,我可以添加功能,就像我现在添加属性一样。

我的第一个想法是可变参数模板(我的引擎是在完全支持C ++ 11功能的基础上构建的):

template <typename Object_t, typename Return_t, typename... Args>
TypeMethod(const char* methodName, Return_t (Object_t::*)(Args&&... args)
{
  //What now?
}

但是,我不知道如何从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::*)())
{
}

函数被递归地'转发'(我知道它不是一个实际的递归),每次只有一个参数。但是,我不认为这对我的情况有何帮助。

3 个答案:

答案 0 :(得分:1)

...

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::*)()
}

我不熟悉可变参数。这是C ++ 11之前的唯一解决方案。但是现在C ++ 11的新功能可以更优雅地解决这个问题。

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

答案 1 :(得分:1)

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

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)...};
}

我们将包扩展放在braced-init-list中,以确保以正确的顺序调用addArgumentType<...>

答案 2 :(得分:1)

使用http://coliru.stacked-crooked.com/a/00750bf7564ab6d4

中的decompose_mem_fun_ptr
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.
}

代表index_sequencemake_index_sequence

#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