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

3

有没有办法在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)

2
运行时间太晚了。你可以在编译时确定,或者根本无法确定。 - n. m.
1个回答

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)按照您的要求工作。

查看实例

但请注意,如果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>))

首先,我们添加一个“fallback”重载,返回一个具有预期大小的类型。然后我们添加另一个重载,修改自己的重载。检查被委托给另一个函数参数。当检查在重载决议期间失败时,参数是不良形式的,替换失败,因为SFINAE很棒!
如果检查通过,则第二个重载是良好形式的,并且更好地匹配,因为省略号在重载决议中的转换序列中具有最低优先级。
宏用于语法糖,因为随后的细节反复输入很乏味。我们在sizeof运算符内部进行重载决议。通过其返回类型选择的重载将反映在sizeof(hasArg1 (member))报告的内容中。因此,我们可以将其与sizeof(tag <1>)(回退)进行比较。由于sizeof是编译时运算符,因此我们有一个编译时常量,告诉我们member的第一个参数是否为ToFind。
为了证明它是编译时常量,我们可以实例化
tag<HAS_ARG1(int, &A::fun1)> test_compile_time;

就像我们在C++98模式下的GCC 4.1.2中这里一样。


这真是神奇的事情!)) 我尝试了相同的代码,但出现了编译错误。在你写的代码之后,它运行得很好:) 谢谢。相信我的代码可以帮助任何人。 - max bushlya
还有一个问题:如果方法被重载了,如何指定这种方法的方法? - max bushlya
@maxbushlya - 你不能这样做。重载或模板化意味着无法进行推导。你需要开始明确指定类型,这不是本意吧? - StoryTeller - Unslander Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接