如何在运行时检查方法签名
How to check method signature in runtime
在 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)
只需删除第一个函数参数:
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
过载,此方法将不起作用。
现在,正如您在问题下所指出的那样。此类事情的运行时检查用处不大。通常您希望在编译时获得该信息,以影响代码生成并可能基于此进行优化。 c++03 与后来的修订相比,其编译时功能有限,但在编译时进行此检查并非不可能。以下是修改代码的方法:
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" 重载,return 是一个具有预期大小的类型。然后我们添加另一个重载,根据您自己的修改。检查被降级到另一个函数参数。当重载解析期间检查失败时,参数格式错误并且替换失败,只剩下后备,因为 SFINAE 太棒了!
如果检查通过,则第二个重载格式正确且匹配更好,因为省略号在重载决策中的转换序列中优先级最低。
宏是为了语法糖而添加的,因为后面的细节要一遍又一遍地输入很乏味。我们在 sizeof
运算符内部进行重载解析。通过其 return 类型选择的过载将反映在 sizeof(hasArg1<ToFind>(member))
报告中。所以我们可以根据 sizeof(tag<1>)
(回退)检查它。由于 sizeof
是一个编译时运算符,我们有一个编译时常量来告诉我们 member
的第一个参数是否是 ToFind
.
并且为了证明它是一个编译时常量,我们可以实例化
tag<HAS_ARG1(int, &A::fun1)> test_compile_time;
在 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)
只需删除第一个函数参数:
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
过载,此方法将不起作用。
现在,正如您在问题下所指出的那样。此类事情的运行时检查用处不大。通常您希望在编译时获得该信息,以影响代码生成并可能基于此进行优化。 c++03 与后来的修订相比,其编译时功能有限,但在编译时进行此检查并非不可能。以下是修改代码的方法:
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" 重载,return 是一个具有预期大小的类型。然后我们添加另一个重载,根据您自己的修改。检查被降级到另一个函数参数。当重载解析期间检查失败时,参数格式错误并且替换失败,只剩下后备,因为 SFINAE 太棒了!
如果检查通过,则第二个重载格式正确且匹配更好,因为省略号在重载决策中的转换序列中优先级最低。
宏是为了语法糖而添加的,因为后面的细节要一遍又一遍地输入很乏味。我们在 sizeof
运算符内部进行重载解析。通过其 return 类型选择的过载将反映在 sizeof(hasArg1<ToFind>(member))
报告中。所以我们可以根据 sizeof(tag<1>)
(回退)检查它。由于 sizeof
是一个编译时运算符,我们有一个编译时常量来告诉我们 member
的第一个参数是否是 ToFind
.
并且为了证明它是一个编译时常量,我们可以实例化
tag<HAS_ARG1(int, &A::fun1)> test_compile_time;