如何在运行时检查方法签名

时间:2018-11-14 06:58:20

标签: c++ c++03

在运行时,是否有任何方法可以确定C ++ 03中方法参数的类型?我正在考虑这样的方式:

#include <cstdio>

template<class T, class U>
struct is_same {
    static const bool result = false;
};

template<class T>
struct is_same<T, T> {
    static const bool result = true;
};

template<class ToFind, class Ret, class T, class Arg>
bool hasArg1(ToFind, Ret (T::*)(Arg)){return is_same<ToFind, Arg>::result;}

template<class ToFind, class Ret, class T, class Arg1, class Arg2>
bool hasArg1(ToFind, Ret (T::*)(Arg1, Arg2)){return is_same<ToFind, Arg1>::result;}

struct A
{
    int fun1(int a){return a+1;}
};

int main() {
    std::printf("int arg1: %s\n", hasArg1(1, &A::fun1) ? "yes" : "no");
}

但是我想要这样的东西:

hasArg1<int>(&A::fun1)

代替

hasArg1(1, &A::fun1)

1 个答案:

答案 0 :(得分:4)

只需删除第一个函数参数:

template<class ToFind, class Ret, class T, class Arg>
bool hasArg1(Ret (T::*)(Arg)){return is_same<ToFind, Arg>::result;}

template<class ToFind, class Ret, class T, class Arg1, class Arg2>
bool hasArg1(Ret (T::*)(Arg1, Arg2)){return is_same<ToFind, Arg1>::result;}

现在hasArg1<int>(&A::fun1)可以按您的意愿工作。

See it Live

但是请记住,如果A::fun1重载,则此方法将无效。


现在,正如您在问题中所指出的。在运行时检查这些东西的用处不大。通常,您希望这些信息在编译时影响代码生成并可能基于此进行优化。与以后的版本相比,的编译时功能受到限制,但是在编译时进行此检查并非并非不可能。这是修改代码的方法:

template<bool C, typename T = void>
struct enable_if;

template<typename T>
struct enable_if<true, T> { typedef T type; };

template<int s> struct tag { char _[s]; };

template<class ToFind>
tag<1> hasArg1(...);

template<class ToFind, class Ret, class T, class Arg>
tag<2> hasArg1(Ret (T::*)(Arg), enable_if<is_same<ToFind, Arg>::result, void>* = 0);

// Add hasArg1 overloads to support members with more arguments

#define HAS_ARG1(ToFind, member) (sizeof(hasArg1<ToFind>(member)) != sizeof(tag<1>))

首先,我们添加一个“后备”重载,该重载返回具有预期大小的类型。然后,我们添加另一个重载,由您自己修改。该检查被移交给另一个函数参数。如果在重载解析期间检查失败,则参数格式错误,替换失败,仅留下后备功能,因为SFINAE很棒!

如果检查通过,则第二个重载格式正确且匹配性更好,因为在重载分辨率中,省略号在转换序列中的优先级最低。

为语法糖添加了宏,因为随后的细节要反复键入很繁琐。我们在sizeof运算符中进行重载解析。通过其返回类型选择的重载将反映在sizeof(hasArg1<ToFind>(member))报告中。因此,我们可以对照sizeof(tag<1>)(后备)进行检查。而且由于sizeof是一个编译时间运算符,所以我们有一个编译时间常数,它告诉我们member的第一个参数是否为ToFind

为了证明它是一个编译时间常数,我们可以实例化

tag<HAS_ARG1(int, &A::fun1)> test_compile_time;

就像我们做的here, in GCC 4.1.2 in C++98 mode一样。